mirror of https://github.com/hak5/openwrt-owl.git
parent
59e3af45d1
commit
f2c1e05f37
|
@ -0,0 +1,491 @@
|
|||
# CONFIG_AEABI is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
# CONFIG_APM_EMULATION is not set
|
||||
# CONFIG_AR6000_WLAN is not set
|
||||
# CONFIG_ARCH_BAST is not set
|
||||
# CONFIG_ARCH_H1940 is not set
|
||||
CONFIG_ARCH_REQUIRE_GPIOLIB=y
|
||||
CONFIG_ARCH_S3C2410=y
|
||||
# CONFIG_ARCH_S3C2440 is not set
|
||||
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
|
||||
# CONFIG_ARCH_SMDK2410 is not set
|
||||
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
|
||||
# CONFIG_ARCH_STMP3XXX is not set
|
||||
# CONFIG_ARCH_SUPPORTS_MSI is not set
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
# CONFIG_ARCH_U300 is not set
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_THUMB=y
|
||||
# CONFIG_ARPD is not set
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
CONFIG_BACKLIGHT_GENERIC=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_BACKLIGHT_PWM is not set
|
||||
CONFIG_BASE_SMALL=0
|
||||
CONFIG_BATTERY_BQ27000_HDQ=y
|
||||
# CONFIG_BATTERY_BQ27x00 is not set
|
||||
# CONFIG_BATTERY_DS2760 is not set
|
||||
# CONFIG_BATTERY_DS2782 is not set
|
||||
# CONFIG_BATTERY_MAX17040 is not set
|
||||
# CONFIG_BINARY_PRINTF is not set
|
||||
CONFIG_BITREVERSE=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BRIDGE_NETFILTER=y
|
||||
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||
CONFIG_CHARGER_PCF50633=y
|
||||
CONFIG_CMDLINE="unused -- bootloader passes ATAG list"
|
||||
CONFIG_COMPAT_BRK=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONSTRUCTORS=y
|
||||
CONFIG_CPU_32=y
|
||||
CONFIG_CPU_32v4T=y
|
||||
CONFIG_CPU_ABRT_EV4T=y
|
||||
CONFIG_CPU_ARM920T=y
|
||||
CONFIG_CPU_CACHE_V4WT=y
|
||||
CONFIG_CPU_CACHE_VIVT=y
|
||||
CONFIG_CPU_COPY_V4WB=y
|
||||
CONFIG_CPU_CP15=y
|
||||
CONFIG_CPU_CP15_MMU=y
|
||||
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
|
||||
# CONFIG_CPU_ICACHE_DISABLE is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_LLSERIAL_S3C2440=y
|
||||
CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y
|
||||
CONFIG_CPU_PABRT_NOIFAR=y
|
||||
CONFIG_CPU_S3C2410_DMA=y
|
||||
CONFIG_CPU_S3C2442=y
|
||||
CONFIG_CPU_S3C244X=y
|
||||
CONFIG_CPU_TLB_V4WBI=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRC7=y
|
||||
CONFIG_CRC_CCITT=y
|
||||
CONFIG_CRC_ITU_T=y
|
||||
CONFIG_CRC_T10DIF=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_MD5=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
# CONFIG_DEBUG_FS is not set
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_DEBUG_S3C_UART=2
|
||||
# CONFIG_DEBUG_USER is not set
|
||||
CONFIG_DECOMPRESS_BZIP2=y
|
||||
CONFIG_DECOMPRESS_GZIP=y
|
||||
CONFIG_DECOMPRESS_LZMA=y
|
||||
CONFIG_DISPLAY_JBT6K74=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_ELF_CORE=y
|
||||
# CONFIG_EMBEDDED is not set
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
CONFIG_FB=y
|
||||
# CONFIG_FB_BACKLIGHT is not set
|
||||
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
|
||||
# CONFIG_FB_BROADSHEET is not set
|
||||
CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
|
||||
# CONFIG_FB_DDC is not set
|
||||
# CONFIG_FB_FOREIGN_ENDIAN is not set
|
||||
# CONFIG_FB_MACMODES is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MODE_HELPERS is not set
|
||||
# CONFIG_FB_S1D13XXX is not set
|
||||
# CONFIG_FB_S3C2410 is not set
|
||||
# CONFIG_FB_SVGALIB is not set
|
||||
# CONFIG_FB_SYS_COPYAREA is not set
|
||||
# CONFIG_FB_SYS_FILLRECT is not set
|
||||
# CONFIG_FB_SYS_FOPS is not set
|
||||
# CONFIG_FB_SYS_IMAGEBLIT is not set
|
||||
# CONFIG_FB_TILEBLITTING is not set
|
||||
# CONFIG_FB_TMIO is not set
|
||||
# CONFIG_FB_VIRTUAL is not set
|
||||
CONFIG_FIQ=y
|
||||
# CONFIG_FIRMWARE_EDID is not set
|
||||
CONFIG_FONTS=y
|
||||
# CONFIG_FONT_10x18 is not set
|
||||
CONFIG_FONT_6x11=y
|
||||
# CONFIG_FONT_7x14 is not set
|
||||
# CONFIG_FONT_8x16 is not set
|
||||
# CONFIG_FONT_8x8 is not set
|
||||
# CONFIG_FONT_ACORN_8x8 is not set
|
||||
# CONFIG_FONT_MINI_4x6 is not set
|
||||
# CONFIG_FONT_PEARL_8x8 is not set
|
||||
# CONFIG_FONT_SUN12x22 is not set
|
||||
# CONFIG_FONT_SUN8x16 is not set
|
||||
# CONFIG_FPE_FASTFPE is not set
|
||||
CONFIG_FPE_NWFPE=y
|
||||
# CONFIG_FPE_NWFPE_XP is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
# CONFIG_FSNOTIFY is not set
|
||||
CONFIG_GENERIC_FIND_LAST_BIT=y
|
||||
CONFIG_GENERIC_GPIO=y
|
||||
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_HAMRADIO is not set
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAVE_AOUT=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
|
||||
CONFIG_HAVE_MLOCK=y
|
||||
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_PWM=y
|
||||
CONFIG_HDQ_GPIO_BITBANG=y
|
||||
CONFIG_HID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_NTRIG=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_HID_SONY=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_SUPPORT=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_HZ=200
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
# CONFIG_I2C_DESIGNWARE is not set
|
||||
CONFIG_I2C_S3C2410=y
|
||||
CONFIG_INET_DIAG=y
|
||||
CONFIG_INET_TCP_DIAG=y
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_INOTIFY=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
# CONFIG_INPUT_GPIO_BUTTONS is not set
|
||||
CONFIG_INPUT_KEYBOARD=y
|
||||
CONFIG_INPUT_LIS302DL=y
|
||||
CONFIG_INPUT_MOUSEDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=480
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=640
|
||||
CONFIG_INPUT_PCF50633_PMU=y
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
# CONFIG_INPUT_YEALINK is not set
|
||||
CONFIG_IP_PNP=y
|
||||
# CONFIG_IP_PNP_BOOTP is not set
|
||||
# CONFIG_IP_PNP_DHCP is not set
|
||||
# CONFIG_IP_PNP_RARP is not set
|
||||
# CONFIG_IP_ROUTE_MULTIPATH is not set
|
||||
# CONFIG_IP_ROUTE_VERBOSE is not set
|
||||
# CONFIG_ISDN is not set
|
||||
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
# CONFIG_KEYBOARD_GPIO is not set
|
||||
# CONFIG_KEYBOARD_LKKBD is not set
|
||||
# CONFIG_KEYBOARD_LM8323 is not set
|
||||
# CONFIG_KEYBOARD_MATRIX is not set
|
||||
# CONFIG_KEYBOARD_NEWTON is not set
|
||||
# CONFIG_KEYBOARD_STOWAWAY is not set
|
||||
# CONFIG_KEYBOARD_SUNKBD is not set
|
||||
# CONFIG_KEYBOARD_XTKBD is not set
|
||||
CONFIG_LCD_CLASS_DEVICE=y
|
||||
# CONFIG_LCD_ILI9320 is not set
|
||||
# CONFIG_LCD_LTV350QV is not set
|
||||
# CONFIG_LCD_PLATFORM is not set
|
||||
# CONFIG_LCD_TDO24M is not set
|
||||
# CONFIG_LCD_VGG2432A4 is not set
|
||||
# CONFIG_LEDS_GPIO is not set
|
||||
CONFIG_LEDS_GTA02_VIBRATOR=y
|
||||
# CONFIG_LEDS_PWM is not set
|
||||
# CONFIG_LEDS_S3C24XX is not set
|
||||
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
|
||||
CONFIG_LOCK_KERNEL=y
|
||||
CONFIG_LOGO=y
|
||||
# CONFIG_LOGO_LINUX_CLUT224 is not set
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_LOG_BUF_SHIFT=18
|
||||
CONFIG_MAC80211_DEFAULT_PS_VALUE=0
|
||||
# CONFIG_MACH_AML_M5900 is not set
|
||||
# CONFIG_MACH_ANUBIS is not set
|
||||
# CONFIG_MACH_AT2440EVB is not set
|
||||
# CONFIG_MACH_JIVE is not set
|
||||
# CONFIG_MACH_MINI2440 is not set
|
||||
# CONFIG_MACH_N30 is not set
|
||||
CONFIG_MACH_NEO1973=y
|
||||
CONFIG_MACH_NEO1973_GTA02=y
|
||||
# CONFIG_MACH_NEXCODER_2440 is not set
|
||||
# CONFIG_MACH_OSIRIS is not set
|
||||
# CONFIG_MACH_OTOM is not set
|
||||
# CONFIG_MACH_QT2410 is not set
|
||||
# CONFIG_MACH_RX3715 is not set
|
||||
# CONFIG_MACH_SMDK2412 is not set
|
||||
# CONFIG_MACH_SMDK2413 is not set
|
||||
# CONFIG_MACH_SMDK2443 is not set
|
||||
# CONFIG_MACH_TCT_HAMMER is not set
|
||||
# CONFIG_MACH_VR1000 is not set
|
||||
# CONFIG_MACH_VSTMS is not set
|
||||
CONFIG_MFD_CORE=y
|
||||
CONFIG_MFD_GLAMO=y
|
||||
CONFIG_MFD_GLAMO_FB=y
|
||||
CONFIG_MFD_GLAMO_GPIO=y
|
||||
# CONFIG_MFD_GLAMO_MCI is not set
|
||||
CONFIG_MFD_PCF50633=y
|
||||
# CONFIG_MFD_T7L66XB is not set
|
||||
# CONFIG_MG_DISK is not set
|
||||
# CONFIG_MISC_DEVICES is not set
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BLOCK=y
|
||||
CONFIG_MMC_BLOCK_BOUNCE=y
|
||||
# CONFIG_MMC_DEBUG is not set
|
||||
# CONFIG_MMC_S3C is not set
|
||||
# CONFIG_MMC_SDHCI is not set
|
||||
# CONFIG_MMC_SPI is not set
|
||||
# CONFIG_MMC_UNSAFE_RESUME is not set
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_MTD_ABSENT=y
|
||||
# CONFIG_MTD_CFI_AMDSTD is not set
|
||||
CONFIG_MTD_CMDLINE_PARTS=y
|
||||
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
|
||||
CONFIG_MTD_CONCAT=y
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_NAND_S3C2410=y
|
||||
# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set
|
||||
# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
|
||||
CONFIG_MTD_NAND_S3C2410_HWECC=y
|
||||
CONFIG_MTD_NAND_VERIFY_WRITE=y
|
||||
CONFIG_MTD_PHYSMAP=y
|
||||
CONFIG_MTD_ROM=y
|
||||
CONFIG_NAMESPACES=y
|
||||
# CONFIG_NETDEV_1000 is not set
|
||||
# CONFIG_NETWORK_FILESYSTEMS is not set
|
||||
# CONFIG_NET_CLS_ACT is not set
|
||||
# CONFIG_NET_ETHERNET is not set
|
||||
# CONFIG_NET_NS is not set
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NO_IOPORT=y
|
||||
CONFIG_NR_TTY_DEVICES=6
|
||||
CONFIG_PAGEFLAGS_EXTENDED=y
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
CONFIG_PCF50633_ADC=y
|
||||
CONFIG_PCF50633_GPIO=y
|
||||
# CONFIG_PCI_SYSCALL is not set
|
||||
# CONFIG_PDA_POWER is not set
|
||||
CONFIG_PLAT_S3C=y
|
||||
CONFIG_PLAT_S3C24XX=y
|
||||
CONFIG_PM=y
|
||||
# CONFIG_PM_DEBUG is not set
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
# CONFIG_POWER_SUPPLY_DEBUG is not set
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_RD_BZIP2=y
|
||||
CONFIG_RD_GZIP=y
|
||||
CONFIG_REGULATOR=y
|
||||
# CONFIG_REGULATOR_DEBUG is not set
|
||||
# CONFIG_REGULATOR_LP3971 is not set
|
||||
# CONFIG_REGULATOR_MAX1586 is not set
|
||||
CONFIG_REGULATOR_PCF50633=y
|
||||
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
|
||||
CONFIG_RFKILL=y
|
||||
CONFIG_RFKILL_INPUT=y
|
||||
CONFIG_RFKILL_LEDS=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_DRV_CMOS is not set
|
||||
CONFIG_RTC_DRV_PCF50633=y
|
||||
# CONFIG_RTC_DRV_RX8025 is not set
|
||||
CONFIG_RTC_DRV_S3C=y
|
||||
CONFIG_S3C2410_CLOCK=y
|
||||
CONFIG_S3C2410_DMA=y
|
||||
# CONFIG_S3C2410_DMA_DEBUG is not set
|
||||
CONFIG_S3C2410_GPIO=y
|
||||
CONFIG_S3C2410_PM=y
|
||||
# CONFIG_S3C2410_PM_CHECK is not set
|
||||
# CONFIG_S3C2410_PM_DEBUG is not set
|
||||
CONFIG_S3C2410_WATCHDOG=y
|
||||
# CONFIG_S3C24XX_ADC is not set
|
||||
CONFIG_S3C24XX_GPIO_EXTRA=64
|
||||
CONFIG_S3C24XX_GPIO_EXTRA64=y
|
||||
CONFIG_S3C24XX_PWM=y
|
||||
# CONFIG_S3C_BOOT_ERROR_RESET is not set
|
||||
CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
|
||||
# CONFIG_S3C_BOOT_WATCHDOG is not set
|
||||
CONFIG_S3C_DEV_USB_HOST=y
|
||||
CONFIG_S3C_DMA=y
|
||||
CONFIG_S3C_GPIO_SPACE=0
|
||||
CONFIG_S3C_LOWLEVEL_UART_PORT=2
|
||||
CONFIG_S3C_PWM=y
|
||||
# CONFIG_SCSI_DMA is not set
|
||||
# CONFIG_SDIO_UART is not set
|
||||
# CONFIG_SERIAL_8250 is not set
|
||||
CONFIG_SERIAL_S3C2440=y
|
||||
CONFIG_SERIAL_SAMSUNG=y
|
||||
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
|
||||
CONFIG_SERIAL_SAMSUNG_UARTS=3
|
||||
CONFIG_SERIO=y
|
||||
# CONFIG_SERIO_RAW is not set
|
||||
# CONFIG_SERIO_SERPORT is not set
|
||||
# CONFIG_SLOW_WORK is not set
|
||||
# CONFIG_SMARTJOYPLUS_FF is not set
|
||||
CONFIG_SND=m
|
||||
# CONFIG_SND_ARM is not set
|
||||
# CONFIG_SND_DRIVERS is not set
|
||||
# CONFIG_SND_EMU10K1_SEQ is not set
|
||||
CONFIG_SND_JACK=y
|
||||
# CONFIG_SND_OPL3_LIB_SEQ is not set
|
||||
# CONFIG_SND_OPL4_LIB_SEQ is not set
|
||||
CONFIG_SND_PCM=m
|
||||
# CONFIG_SND_RAWMIDI_SEQ is not set
|
||||
CONFIG_SND_S3C24XX_SOC=m
|
||||
CONFIG_SND_S3C24XX_SOC_I2S=m
|
||||
# CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650 is not set
|
||||
CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753=m
|
||||
# CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X is not set
|
||||
# CONFIG_SND_SBAWE_SEQ is not set
|
||||
CONFIG_SND_SOC=m
|
||||
# CONFIG_SND_SOC_ALL_CODECS is not set
|
||||
CONFIG_SND_SOC_I2C_AND_SPI=m
|
||||
CONFIG_SND_SOC_WM8753=m
|
||||
CONFIG_SND_TIMER=m
|
||||
# CONFIG_SND_USB is not set
|
||||
# CONFIG_SND_VERBOSE_PROCFS is not set
|
||||
CONFIG_SOUND=m
|
||||
# CONFIG_SOUND_OSS_CORE is not set
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_BITBANG=y
|
||||
CONFIG_SPI_GPIO=y
|
||||
CONFIG_SPI_MASTER=y
|
||||
CONFIG_SPI_S3C24XX=y
|
||||
CONFIG_SPI_S3C24XX_GPIO=y
|
||||
# CONFIG_SPI_SPIDEV is not set
|
||||
CONFIG_SPLIT_PTLOCK_CPUS=4096
|
||||
# CONFIG_SQUASHFS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
|
||||
CONFIG_SYSFS_DEPRECATED=y
|
||||
CONFIG_SYSFS_DEPRECATED_V2=y
|
||||
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
|
||||
CONFIG_TCP_MD5SIG=y
|
||||
# CONFIG_TOUCHSCREEN_AD7877 is not set
|
||||
# CONFIG_TOUCHSCREEN_AD7879 is not set
|
||||
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
|
||||
# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
|
||||
# CONFIG_TOUCHSCREEN_ADS7846 is not set
|
||||
# CONFIG_TOUCHSCREEN_EETI is not set
|
||||
# CONFIG_TOUCHSCREEN_ELO is not set
|
||||
CONFIG_TOUCHSCREEN_FILTER=y
|
||||
CONFIG_TOUCHSCREEN_FILTER_GROUP=y
|
||||
CONFIG_TOUCHSCREEN_FILTER_LINEAR=y
|
||||
CONFIG_TOUCHSCREEN_FILTER_MEAN=y
|
||||
CONFIG_TOUCHSCREEN_FILTER_MEDIAN=y
|
||||
# CONFIG_TOUCHSCREEN_FUJITSU is not set
|
||||
# CONFIG_TOUCHSCREEN_GUNZE is not set
|
||||
# CONFIG_TOUCHSCREEN_INEXIO is not set
|
||||
# CONFIG_TOUCHSCREEN_MK712 is not set
|
||||
# CONFIG_TOUCHSCREEN_MTOUCH is not set
|
||||
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
|
||||
CONFIG_TOUCHSCREEN_S3C2410=y
|
||||
# CONFIG_TOUCHSCREEN_S3C2410_DEBUG is not set
|
||||
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
|
||||
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
|
||||
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
|
||||
# CONFIG_TOUCHSCREEN_TSC2007 is not set
|
||||
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
|
||||
# CONFIG_TOUCHSCREEN_W90X900 is not set
|
||||
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
|
||||
CONFIG_TRACING_SUPPORT=y
|
||||
# CONFIG_UACCESS_WITH_MEMCPY is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
# CONFIG_USB_ARCH_HAS_EHCI is not set
|
||||
# CONFIG_USB_AUDIO is not set
|
||||
# CONFIG_USB_CDC_COMPOSITE is not set
|
||||
# CONFIG_USB_DEVICEFS is not set
|
||||
CONFIG_USB_ETH=y
|
||||
CONFIG_USB_ETH_RNDIS=y
|
||||
# CONFIG_USB_FILE_STORAGE is not set
|
||||
CONFIG_USB_GADGET=y
|
||||
# CONFIG_USB_GADGETFS is not set
|
||||
# CONFIG_USB_GADGET_AMD5536UDC is not set
|
||||
# CONFIG_USB_GADGET_AT91 is not set
|
||||
# CONFIG_USB_GADGET_ATMEL_USBA is not set
|
||||
# CONFIG_USB_GADGET_CI13XXX is not set
|
||||
# CONFIG_USB_GADGET_DEBUG_FILES is not set
|
||||
# CONFIG_USB_GADGET_DUALSPEED is not set
|
||||
# CONFIG_USB_GADGET_DUMMY_HCD is not set
|
||||
# CONFIG_USB_GADGET_FSL_QE is not set
|
||||
# CONFIG_USB_GADGET_FSL_USB2 is not set
|
||||
# CONFIG_USB_GADGET_GOKU is not set
|
||||
# CONFIG_USB_GADGET_IMX is not set
|
||||
# CONFIG_USB_GADGET_LANGWELL is not set
|
||||
# CONFIG_USB_GADGET_LH7A40X is not set
|
||||
# CONFIG_USB_GADGET_M66592 is not set
|
||||
# CONFIG_USB_GADGET_MUSB_HDRC is not set
|
||||
# CONFIG_USB_GADGET_NET2280 is not set
|
||||
# CONFIG_USB_GADGET_OMAP is not set
|
||||
# CONFIG_USB_GADGET_PXA25X is not set
|
||||
# CONFIG_USB_GADGET_PXA27X is not set
|
||||
CONFIG_USB_GADGET_S3C2410=y
|
||||
# CONFIG_USB_GADGET_S3C_HSOTG is not set
|
||||
CONFIG_USB_GADGET_SELECTED=y
|
||||
CONFIG_USB_GADGET_VBUS_DRAW=500
|
||||
# CONFIG_USB_G_PRINTER is not set
|
||||
# CONFIG_USB_G_SERIAL is not set
|
||||
CONFIG_USB_HID=y
|
||||
# CONFIG_USB_MIDI_GADGET is not set
|
||||
# CONFIG_USB_MUSB_HDRC is not set
|
||||
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
|
||||
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_S3C2410=y
|
||||
# CONFIG_USB_S3C2410_DEBUG is not set
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_SUSPEND=y
|
||||
# CONFIG_USB_ZERO is not set
|
||||
# CONFIG_USER_NS is not set
|
||||
CONFIG_VECTORS_BASE=0xffff0000
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
CONFIG_VIDEO_OUTPUT_CONTROL=y
|
||||
# CONFIG_VLAN_8021Q is not set
|
||||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_W1=m
|
||||
# CONFIG_WLAN_80211 is not set
|
||||
CONFIG_ZBOOT_ROM_BSS=0x0
|
||||
CONFIG_ZBOOT_ROM_TEXT=0x0
|
||||
CONFIG_ZONE_DMA_FLAG=0
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Bluetooth PM code for the Openmoko Freerunner GSM Phone
|
||||
*
|
||||
* (C) 2007 by Openmoko Inc.
|
||||
* Author: Harald Welte <laforge@openmoko.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/err.h>
|
||||
#include <mach/gpio-fns.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <mach/gta02.h>
|
||||
#include <linux/mfd/pcf50633/gpio.h>
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define DRVMSG "Openmoko Freerunner Bluetooth Power Management"
|
||||
|
||||
struct gta02_pm_bt_data {
|
||||
struct regulator *regulator;
|
||||
struct rfkill *rfkill;
|
||||
int pre_resume_state;
|
||||
};
|
||||
|
||||
static ssize_t bt_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!strcmp(attr->attr.name, "power_on")) {
|
||||
if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN))
|
||||
ret = 1;
|
||||
} else if (!strcmp(attr->attr.name, "reset")) {
|
||||
if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN) == 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return strlcpy(buf, "0\n", 3);
|
||||
} else {
|
||||
return strlcpy(buf, "1\n", 3);
|
||||
}
|
||||
}
|
||||
|
||||
static void __gta02_pm_bt_toggle_radio(struct device *dev, unsigned int on)
|
||||
{
|
||||
struct gta02_pm_bt_data *bt_data = dev_get_drvdata(dev);
|
||||
|
||||
dev_info(dev, "__gta02_pm_bt_toggle_radio %d\n", on);
|
||||
|
||||
bt_data = dev_get_drvdata(dev);
|
||||
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, !on);
|
||||
|
||||
if (on) {
|
||||
if (!regulator_is_enabled(bt_data->regulator))
|
||||
regulator_enable(bt_data->regulator);
|
||||
} else {
|
||||
if (regulator_is_enabled(bt_data->regulator))
|
||||
regulator_disable(bt_data->regulator);
|
||||
}
|
||||
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, on);
|
||||
}
|
||||
|
||||
|
||||
static int bt_rfkill_set_block(void *data, bool blocked)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
__gta02_pm_bt_toggle_radio(dev, !blocked);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops gta02_bt_rfkill_ops = {
|
||||
.set_block = bt_rfkill_set_block,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t bt_write(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long on = simple_strtoul(buf, NULL, 10);
|
||||
struct gta02_pm_bt_data *bt_data = dev_get_drvdata(dev);
|
||||
|
||||
if (!strcmp(attr->attr.name, "power_on")) {
|
||||
rfkill_set_sw_state(bt_data->rfkill, on ? 1 : 0);
|
||||
|
||||
__gta02_pm_bt_toggle_radio(dev, on);
|
||||
} else if (!strcmp(attr->attr.name, "reset")) {
|
||||
/* reset is low-active, so we need to invert */
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, on ? 0 : 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_on, 0644, bt_read, bt_write);
|
||||
static DEVICE_ATTR(reset, 0644, bt_read, bt_write);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int gta02_bt_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct gta02_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
dev_dbg(&pdev->dev, DRVMSG ": suspending\n");
|
||||
|
||||
bt_data->pre_resume_state = s3c2410_gpio_getpin(GTA02_GPIO_BT_EN);
|
||||
__gta02_pm_bt_toggle_radio(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gta02_bt_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct gta02_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
|
||||
dev_dbg(&pdev->dev, DRVMSG ": resuming\n");
|
||||
|
||||
__gta02_pm_bt_toggle_radio(&pdev->dev, bt_data->pre_resume_state);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define gta02_bt_suspend NULL
|
||||
#define gta02_bt_resume NULL
|
||||
#endif
|
||||
|
||||
static struct attribute *gta02_bt_sysfs_entries[] = {
|
||||
&dev_attr_power_on.attr,
|
||||
&dev_attr_reset.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group gta02_bt_attr_group = {
|
||||
.name = NULL,
|
||||
.attrs = gta02_bt_sysfs_entries,
|
||||
};
|
||||
|
||||
static int __init gta02_bt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rfkill *rfkill;
|
||||
struct regulator *regulator;
|
||||
struct gta02_pm_bt_data *bt_data;
|
||||
int ret;
|
||||
|
||||
dev_info(&pdev->dev, DRVMSG ": starting\n");
|
||||
|
||||
bt_data = kzalloc(sizeof(*bt_data), GFP_KERNEL);
|
||||
dev_set_drvdata(&pdev->dev, bt_data);
|
||||
|
||||
regulator = regulator_get(&pdev->dev, "BT_3V2");
|
||||
if (IS_ERR(regulator))
|
||||
return -ENODEV;
|
||||
|
||||
bt_data->regulator = regulator;
|
||||
|
||||
/* this tests the true physical state of the regulator... */
|
||||
if (regulator_is_enabled(regulator)) {
|
||||
/*
|
||||
* but these only operate on the logical state of the
|
||||
* regulator... so we need to logicaly "adopt" it on
|
||||
* to turn it off
|
||||
*/
|
||||
regulator_enable(regulator);
|
||||
regulator_disable(regulator);
|
||||
}
|
||||
|
||||
/* we pull reset to low to make sure that the chip doesn't
|
||||
* drain power through the reset line */
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_BT_EN, 0);
|
||||
|
||||
rfkill = rfkill_alloc(pdev->name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
|
||||
>a02_bt_rfkill_ops, &pdev->dev);
|
||||
|
||||
if (!rfkill) {
|
||||
dev_err(&pdev->dev, "Failed to allocate rfkill\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rfkill_init_sw_state(rfkill, 0);
|
||||
|
||||
ret = rfkill_register(rfkill);
|
||||
if (ret) {
|
||||
rfkill_destroy(rfkill);
|
||||
dev_err(&pdev->dev, "Failed to register rfkill\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bt_data->rfkill = rfkill;
|
||||
|
||||
return sysfs_create_group(&pdev->dev.kobj, >a02_bt_attr_group);
|
||||
}
|
||||
|
||||
static int gta02_bt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gta02_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
|
||||
struct regulator *regulator;
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, >a02_bt_attr_group);
|
||||
|
||||
if (bt_data->rfkill) {
|
||||
rfkill_destroy(bt_data->rfkill);
|
||||
}
|
||||
|
||||
if (!bt_data || !bt_data->regulator)
|
||||
return 0;
|
||||
|
||||
regulator = bt_data->regulator;
|
||||
|
||||
/* Make sure regulator is disabled before calling regulator_put */
|
||||
if (regulator_is_enabled(regulator))
|
||||
regulator_disable(regulator);
|
||||
|
||||
regulator_put(regulator);
|
||||
|
||||
kfree(bt_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gta02_bt_driver = {
|
||||
.probe = gta02_bt_probe,
|
||||
.remove = gta02_bt_remove,
|
||||
.suspend = gta02_bt_suspend,
|
||||
.resume = gta02_bt_resume,
|
||||
.driver = {
|
||||
.name = "gta02-pm-bt",
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit gta02_bt_init(void)
|
||||
{
|
||||
return platform_driver_register(>a02_bt_driver);
|
||||
}
|
||||
|
||||
static void gta02_bt_exit(void)
|
||||
{
|
||||
platform_driver_unregister(>a02_bt_driver);
|
||||
}
|
||||
|
||||
module_init(gta02_bt_init);
|
||||
module_exit(gta02_bt_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
|
||||
MODULE_DESCRIPTION(DRVMSG);
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* GPS Power Management code for the Openmoko Freerunner GSM Phone
|
||||
*
|
||||
* (C) 2007-2009 by Openmoko Inc.
|
||||
* Author: Harald Welte <laforge@openmoko.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio-fns.h>
|
||||
#include <mach/cpu.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <mach/gta02.h>
|
||||
#include <linux/mfd/pcf50633/core.h>
|
||||
#include <linux/mfd/pcf50633/pmic.h>
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
struct gta02_pm_gps_data {
|
||||
#ifdef CONFIG_PM
|
||||
int keep_on_in_suspend;
|
||||
#endif
|
||||
int power_was_on;
|
||||
struct regulator *regulator;
|
||||
};
|
||||
|
||||
static struct gta02_pm_gps_data gta02_gps;
|
||||
|
||||
int gta02_pm_gps_is_on(void)
|
||||
{
|
||||
return gta02_gps.power_was_on;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gta02_pm_gps_is_on);
|
||||
|
||||
/* This is the POWERON pin */
|
||||
static void gps_pwron_set(int on)
|
||||
{
|
||||
if (on) {
|
||||
/* return UART pins to being UART pins */
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(4), S3C2410_GPH4_TXD1);
|
||||
/* remove pulldown now it won't be floating any more */
|
||||
s3c2410_gpio_pullup(S3C2410_GPH(5), 0);
|
||||
|
||||
if (!gta02_gps.power_was_on)
|
||||
regulator_enable(gta02_gps.regulator);
|
||||
} else {
|
||||
/*
|
||||
* take care not to power unpowered GPS from UART TX
|
||||
* return them to GPIO and force low
|
||||
*/
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(4), S3C2410_GPIO_OUTPUT);
|
||||
s3c2410_gpio_setpin(S3C2410_GPH(4), 0);
|
||||
/* don't let RX from unpowered GPS float */
|
||||
s3c2410_gpio_pullup(S3C2410_GPH(5), 1);
|
||||
if (gta02_gps.power_was_on)
|
||||
regulator_disable(gta02_gps.regulator);
|
||||
}
|
||||
}
|
||||
|
||||
static int gps_pwron_get(void)
|
||||
{
|
||||
return regulator_is_enabled(gta02_gps.regulator);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* This is the flag for keeping gps ON during suspend */
|
||||
static void gps_keep_on_in_suspend_set(int on)
|
||||
{
|
||||
gta02_gps.keep_on_in_suspend = on;
|
||||
}
|
||||
|
||||
static int gps_keep_on_in_suspend_get(void)
|
||||
{
|
||||
return gta02_gps.keep_on_in_suspend;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t power_gps_read(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!strcmp(attr->attr.name, "power_on") ||
|
||||
!strcmp(attr->attr.name, "pwron")) {
|
||||
ret = gps_pwron_get();
|
||||
#ifdef CONFIG_PM
|
||||
} else if (!strcmp(attr->attr.name, "keep_on_in_suspend")) {
|
||||
ret = gps_keep_on_in_suspend_get();
|
||||
#endif
|
||||
}
|
||||
if (ret)
|
||||
return strlcpy(buf, "1\n", 3);
|
||||
else
|
||||
return strlcpy(buf, "0\n", 3);
|
||||
}
|
||||
|
||||
static ssize_t power_gps_write(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long on = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (!strcmp(attr->attr.name, "power_on") ||
|
||||
!strcmp(attr->attr.name, "pwron")) {
|
||||
gps_pwron_set(on);
|
||||
gta02_gps.power_was_on = !!on;
|
||||
#ifdef CONFIG_PM
|
||||
} else if (!strcmp(attr->attr.name, "keep_on_in_suspend")) {
|
||||
gps_keep_on_in_suspend_set(on);
|
||||
#endif
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int gta02_pm_gps_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
{
|
||||
if (!gta02_gps.keep_on_in_suspend ||
|
||||
!gta02_gps.power_was_on)
|
||||
gps_pwron_set(0);
|
||||
else
|
||||
dev_warn(&pdev->dev, "GTA02: keeping gps ON "
|
||||
"during suspend\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gta02_pm_gps_resume(struct platform_device *pdev)
|
||||
{
|
||||
if (!gta02_gps.keep_on_in_suspend && gta02_gps.power_was_on)
|
||||
gps_pwron_set(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(keep_on_in_suspend, 0644, power_gps_read, power_gps_write);
|
||||
#else
|
||||
#define gta02_pm_gps_suspend NULL
|
||||
#define gta02_pm_gps_resume NULL
|
||||
#endif
|
||||
|
||||
static DEVICE_ATTR(power_on, 0644, power_gps_read, power_gps_write);
|
||||
|
||||
static struct attribute *gta02_gps_sysfs_entries[] = {
|
||||
&dev_attr_power_on.attr,
|
||||
#ifdef CONFIG_PM
|
||||
&dev_attr_keep_on_in_suspend.attr,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group gta02_gps_attr_group = {
|
||||
.name = NULL,
|
||||
.attrs = gta02_gps_sysfs_entries,
|
||||
};
|
||||
|
||||
static int __init gta02_pm_gps_probe(struct platform_device *pdev)
|
||||
{
|
||||
gta02_gps.regulator = regulator_get(&pdev->dev, "RF_3V");
|
||||
if (IS_ERR(gta02_gps.regulator)) {
|
||||
dev_err(&pdev->dev, "probe failed %ld\n",
|
||||
PTR_ERR(gta02_gps.regulator));
|
||||
|
||||
return PTR_ERR(gta02_gps.regulator);
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "starting\n");
|
||||
|
||||
/*
|
||||
* Here we should call the code that handles the set GPS power
|
||||
* off action. But, the regulator API does not allow us to
|
||||
* reassert regulator state, and when we read the regulator API
|
||||
* logical state, it can differ from the actual state, So
|
||||
* a workaround for this is to just set the regulator off in the
|
||||
* PMU directly. Because that's different from normal flow, we
|
||||
* have to reproduce other things from the OFF action here too.
|
||||
*/
|
||||
|
||||
/*
|
||||
* u-boot enables LDO5 (GPS), which doesn't make sense and
|
||||
* causes confusion. We therefore disable the regulator here.
|
||||
*/
|
||||
pcf50633_reg_write(gta02_pcf, PCF50633_REG_LDO5ENA, 0);
|
||||
|
||||
/*
|
||||
* take care not to power unpowered GPS from UART TX
|
||||
* return them to GPIO and force low
|
||||
*/
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(4), S3C2410_GPIO_OUTPUT);
|
||||
s3c2410_gpio_setpin(S3C2410_GPH(4), 0);
|
||||
/* don't let RX from unpowered GPS float */
|
||||
s3c2410_gpio_pullup(S3C2410_GPH(5), 1);
|
||||
|
||||
return sysfs_create_group(&pdev->dev.kobj,
|
||||
>a02_gps_attr_group);
|
||||
}
|
||||
|
||||
static int gta02_pm_gps_remove(struct platform_device *pdev)
|
||||
{
|
||||
regulator_put(gta02_gps.regulator);
|
||||
sysfs_remove_group(&pdev->dev.kobj, >a02_gps_attr_group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gta02_pm_gps_driver = {
|
||||
.probe = gta02_pm_gps_probe,
|
||||
.remove = gta02_pm_gps_remove,
|
||||
.suspend = gta02_pm_gps_suspend,
|
||||
.resume = gta02_pm_gps_resume,
|
||||
.driver = {
|
||||
.name = "gta02-pm-gps",
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit gta02_pm_gps_init(void)
|
||||
{
|
||||
return platform_driver_register(>a02_pm_gps_driver);
|
||||
}
|
||||
|
||||
static void gta02_pm_gps_exit(void)
|
||||
{
|
||||
platform_driver_unregister(>a02_pm_gps_driver);
|
||||
}
|
||||
|
||||
module_init(gta02_pm_gps_init);
|
||||
module_exit(gta02_pm_gps_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* GSM Management code for the Openmoko Freerunner GSM Phone
|
||||
*
|
||||
* (C) 2007 by Openmoko Inc.
|
||||
* Author: Harald Welte <laforge@openmoko.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/cpu.h>
|
||||
|
||||
#include <mach/gta02.h>
|
||||
#include <linux/mfd/pcf50633/gpio.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-gpioj.h>
|
||||
|
||||
int gta_gsm_interrupts;
|
||||
EXPORT_SYMBOL(gta_gsm_interrupts);
|
||||
|
||||
extern void s3c24xx_serial_console_set_silence(int);
|
||||
|
||||
struct gta02pm_priv {
|
||||
int gpio_ndl_gsm;
|
||||
struct console *con;
|
||||
};
|
||||
|
||||
static struct gta02pm_priv gta02_gsm;
|
||||
|
||||
static struct console *find_s3c24xx_console(void)
|
||||
{
|
||||
struct console *con;
|
||||
|
||||
acquire_console_sem();
|
||||
|
||||
for (con = console_drivers; con; con = con->next) {
|
||||
if (!strcmp(con->name, "ttySAC"))
|
||||
break;
|
||||
}
|
||||
|
||||
release_console_sem();
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
static ssize_t gsm_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
if (!strcmp(attr->attr.name, "power_on")) {
|
||||
if (pcf50633_gpio_get(gta02_pcf, PCF50633_GPIO2))
|
||||
goto out_1;
|
||||
} else if (!strcmp(attr->attr.name, "download")) {
|
||||
if (!s3c2410_gpio_getpin(GTA02_GPIO_nDL_GSM))
|
||||
goto out_1;
|
||||
} else if (!strcmp(attr->attr.name, "flowcontrolled")) {
|
||||
if (s3c2410_gpio_getcfg(S3C2410_GPH(1)) == S3C2410_GPIO_OUTPUT)
|
||||
goto out_1;
|
||||
}
|
||||
|
||||
return strlcpy(buf, "0\n", 3);
|
||||
out_1:
|
||||
return strlcpy(buf, "1\n", 3);
|
||||
}
|
||||
|
||||
static void gsm_on_off(struct device *dev, int on)
|
||||
{
|
||||
if (!on) {
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_INPUT);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPIO_INPUT);
|
||||
|
||||
pcf50633_gpio_set(gta02_pcf, PCF50633_GPIO2, 0);
|
||||
|
||||
if (gta02_gsm.con) {
|
||||
s3c24xx_serial_console_set_silence(0);
|
||||
console_start(gta02_gsm.con);
|
||||
|
||||
dev_dbg(dev, "powered down gta02 GSM, enabling "
|
||||
"serial console\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (gta02_gsm.con) {
|
||||
dev_dbg(dev, "powering up GSM, thus "
|
||||
"disconnecting serial console\n");
|
||||
|
||||
console_stop(gta02_gsm.con);
|
||||
s3c24xx_serial_console_set_silence(1);
|
||||
}
|
||||
|
||||
/* allow UART to talk to GSM side now we will power it */
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPH1_nRTS0);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
|
||||
|
||||
pcf50633_gpio_set(gta02_pcf, PCF50633_GPIO2, 7);
|
||||
|
||||
msleep(100);
|
||||
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_MODEM_ON, 1);
|
||||
msleep(500);
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_MODEM_ON, 0);
|
||||
|
||||
/*
|
||||
* workaround for calypso firmware moko10 and earlier,
|
||||
* without this it will leave IRQ line high after
|
||||
* booting
|
||||
*/
|
||||
s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
|
||||
msleep(1000);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPH1_nRTS0);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t gsm_write(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long on = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (!strcmp(attr->attr.name, "power_on")) {
|
||||
gsm_on_off(dev, on);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(attr->attr.name, "download")) {
|
||||
/*
|
||||
* the keyboard / buttons driver requests and enables
|
||||
* the JACK_INSERT IRQ. We have to take care about
|
||||
* not enabling and disabling the IRQ when it was
|
||||
* already in that state or we get "unblanaced IRQ"
|
||||
* kernel warnings and stack dumps. So we use the
|
||||
* copy of the ndl_gsm state to figure out if we should
|
||||
* enable or disable the jack interrupt
|
||||
*/
|
||||
if (on) {
|
||||
if (gta02_gsm.gpio_ndl_gsm)
|
||||
disable_irq(gpio_to_irq(
|
||||
GTA02_GPIO_JACK_INSERT));
|
||||
} else {
|
||||
if (!gta02_gsm.gpio_ndl_gsm)
|
||||
enable_irq(gpio_to_irq(
|
||||
GTA02_GPIO_JACK_INSERT));
|
||||
}
|
||||
|
||||
gta02_gsm.gpio_ndl_gsm = !on;
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, !on);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(attr->attr.name, "flowcontrolled")) {
|
||||
if (on) {
|
||||
gta_gsm_interrupts = 0;
|
||||
s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
|
||||
} else
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPH1_nRTS0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_on, 0644, gsm_read, gsm_write);
|
||||
static DEVICE_ATTR(reset, 0644, gsm_read, gsm_write);
|
||||
static DEVICE_ATTR(download, 0644, gsm_read, gsm_write);
|
||||
static DEVICE_ATTR(flowcontrolled, 0644, gsm_read, gsm_write);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int gta02_gsm_resume(struct platform_device *pdev);
|
||||
static int gta02_gsm_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
/* GPIO state is saved/restored by S3C2410 core GPIO driver, so we
|
||||
* don't need to do much here. */
|
||||
|
||||
/* If flowcontrol asserted, abort if GSM already interrupted */
|
||||
if (s3c2410_gpio_getcfg(S3C2410_GPH(1)) == S3C2410_GPIO_OUTPUT) {
|
||||
if (gta_gsm_interrupts)
|
||||
goto busy;
|
||||
}
|
||||
|
||||
/* disable DL GSM to prevent jack_insert becoming 'floating' */
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, 1);
|
||||
return 0;
|
||||
|
||||
busy:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int
|
||||
gta02_gsm_suspend_late(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
/* Last chance: abort if GSM already interrupted */
|
||||
if (s3c2410_gpio_getcfg(S3C2410_GPH(1)) == S3C2410_GPIO_OUTPUT) {
|
||||
if (gta_gsm_interrupts)
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gta02_gsm_resume(struct platform_device *pdev)
|
||||
{
|
||||
/* GPIO state is saved/restored by S3C2410 core GPIO driver, so we
|
||||
* don't need to do much here. */
|
||||
|
||||
/* Make sure that the kernel console on the serial port is still
|
||||
* disabled. FIXME: resume ordering race with serial driver! */
|
||||
if (gta02_gsm.con && s3c2410_gpio_getpin(GTA02_GPIO_MODEM_ON))
|
||||
console_stop(gta02_gsm.con);
|
||||
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, gta02_gsm.gpio_ndl_gsm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define gta02_gsm_suspend NULL
|
||||
#define gta02_gsm_suspend_late NULL
|
||||
#define gta02_gsm_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct attribute *gta02_gsm_sysfs_entries[] = {
|
||||
&dev_attr_power_on.attr,
|
||||
&dev_attr_reset.attr,
|
||||
&dev_attr_download.attr,
|
||||
&dev_attr_flowcontrolled.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group gta02_gsm_attr_group = {
|
||||
.name = NULL,
|
||||
.attrs = gta02_gsm_sysfs_entries,
|
||||
};
|
||||
|
||||
static int __init gta02_gsm_probe(struct platform_device *pdev)
|
||||
{
|
||||
switch (S3C_SYSTEM_REV_ATAG) {
|
||||
case GTA02v1_SYSTEM_REV:
|
||||
case GTA02v2_SYSTEM_REV:
|
||||
case GTA02v3_SYSTEM_REV:
|
||||
case GTA02v4_SYSTEM_REV:
|
||||
case GTA02v5_SYSTEM_REV:
|
||||
case GTA02v6_SYSTEM_REV:
|
||||
break;
|
||||
default:
|
||||
dev_warn(&pdev->dev, "Unknown Freerunner Revision 0x%x, "
|
||||
"some PM features not available!!!\n",
|
||||
system_rev);
|
||||
break;
|
||||
}
|
||||
|
||||
gta02_gsm.con = find_s3c24xx_console();
|
||||
if (!gta02_gsm.con)
|
||||
dev_warn(&pdev->dev,
|
||||
"cannot find S3C24xx console driver\n");
|
||||
|
||||
/* note that download initially disabled, and enforce that */
|
||||
gta02_gsm.gpio_ndl_gsm = 1;
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nDL_GSM, 1);
|
||||
|
||||
/* GSM is to be initially off (at boot, or if this module inserted) */
|
||||
gsm_on_off(&pdev->dev, 0);
|
||||
|
||||
return sysfs_create_group(&pdev->dev.kobj, >a02_gsm_attr_group);
|
||||
}
|
||||
|
||||
static int gta02_gsm_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_group(&pdev->dev.kobj, >a02_gsm_attr_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gta02_gsm_driver = {
|
||||
.probe = gta02_gsm_probe,
|
||||
.remove = gta02_gsm_remove,
|
||||
.suspend = gta02_gsm_suspend,
|
||||
.suspend_late = gta02_gsm_suspend_late,
|
||||
.resume = gta02_gsm_resume,
|
||||
.driver = {
|
||||
.name = "gta02-pm-gsm",
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit gta02_gsm_init(void)
|
||||
{
|
||||
return platform_driver_register(>a02_gsm_driver);
|
||||
}
|
||||
|
||||
static void gta02_gsm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(>a02_gsm_driver);
|
||||
}
|
||||
|
||||
module_init(gta02_gsm_init);
|
||||
module_exit(gta02_gsm_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
|
||||
MODULE_DESCRIPTION("Openmoko Freerunner GSM Power Management");
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* GTA02 WLAN power management
|
||||
*
|
||||
* (C) 2008, 2009 by Openmoko Inc.
|
||||
* Author: Andy Green <andy@openmoko.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <mach/gta02.h>
|
||||
#include <mach/gta02-pm-wlan.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-gpioj.h>
|
||||
#include <mach/gpio-fns.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
||||
|
||||
/* ----- Module hardware reset ("power") ----------------------------------- */
|
||||
|
||||
|
||||
void gta02_wlan_reset(int assert_reset)
|
||||
{
|
||||
if (assert_reset) {
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nWLAN_RESET, 0);
|
||||
msleep(200); /* probably excessive but we don't have specs */
|
||||
} else {
|
||||
s3c2410_gpio_setpin(GTA02_GPIO_nWLAN_RESET, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- rfkill ------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* S3C MCI handles suspend/resume through device removal/insertion. In order to
|
||||
* preserve rfkill state, as required in clause 7 of section 3.1 in rfkill.txt,
|
||||
* we therefore need to maintain rfkill state outside the driver.
|
||||
*
|
||||
* This platform driver is as good a place as any other.
|
||||
*/
|
||||
|
||||
static int (*gta02_wlan_rfkill_cb)(void *user, int on);
|
||||
static void *gta02_wlan_rfkill_user;
|
||||
static DEFINE_MUTEX(gta02_wlan_rfkill_lock);
|
||||
static int gta02_wlan_rfkill_on;
|
||||
|
||||
/*
|
||||
* gta02_wlan_query_rfkill_lock is used to obtain the rfkill state before the
|
||||
* driver is ready to process rfkill callbacks. To prevent the state from
|
||||
* changing until the driver has completed its initialization, we grab and hold
|
||||
* the rfkill lock.
|
||||
*
|
||||
* A call to gta02_wlan_query_rfkill_lock must be followed by either
|
||||
* - a call to gta02_wlan_set_rfkill_cb, to complete the setup, or
|
||||
* - a call to gta02_wlan_query_rfkill_unlock to abort the setup process.
|
||||
*/
|
||||
|
||||
int gta02_wlan_query_rfkill_lock(void)
|
||||
{
|
||||
mutex_lock(>a02_wlan_rfkill_lock);
|
||||
return gta02_wlan_rfkill_on;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gta02_wlan_query_rfkill_lock);
|
||||
|
||||
void gta02_wlan_query_rfkill_unlock(void)
|
||||
{
|
||||
mutex_unlock(>a02_wlan_rfkill_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gta02_wlan_query_rfkill_unlock);
|
||||
|
||||
void gta02_wlan_set_rfkill_cb(int (*cb)(void *user, int on), void *user)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(>a02_wlan_rfkill_lock));
|
||||
BUG_ON(gta02_wlan_rfkill_cb);
|
||||
gta02_wlan_rfkill_cb = cb;
|
||||
gta02_wlan_rfkill_user = user;
|
||||
mutex_unlock(>a02_wlan_rfkill_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gta02_wlan_set_rfkill_cb);
|
||||
|
||||
void gta02_wlan_clear_rfkill_cb(void)
|
||||
{
|
||||
mutex_lock(>a02_wlan_rfkill_lock);
|
||||
BUG_ON(!gta02_wlan_rfkill_cb);
|
||||
gta02_wlan_rfkill_cb = NULL;
|
||||
mutex_unlock(>a02_wlan_rfkill_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gta02_wlan_clear_rfkill_cb);
|
||||
|
||||
static int gta02_wlan_set_radio_block(void *data, bool blocked)
|
||||
{
|
||||
struct device *dev = data;
|
||||
int res = 0;
|
||||
|
||||
dev_dbg(dev, "gta02_wlan_toggle_radio: blocked %d (%p)\n",
|
||||
blocked, gta02_wlan_rfkill_cb);
|
||||
mutex_lock(>a02_wlan_rfkill_lock);
|
||||
if (gta02_wlan_rfkill_cb)
|
||||
res = gta02_wlan_rfkill_cb(gta02_wlan_rfkill_user, !blocked);
|
||||
if (!res)
|
||||
gta02_wlan_rfkill_on = !blocked;
|
||||
mutex_unlock(>a02_wlan_rfkill_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops gta02_wlan_rfkill_ops = {
|
||||
.set_block = gta02_wlan_set_radio_block,
|
||||
};
|
||||
|
||||
/* ----- Initialization/removal -------------------------------------------- */
|
||||
|
||||
|
||||
static int __init gta02_wlan_probe(struct platform_device *pdev)
|
||||
{
|
||||
/* default-on for now */
|
||||
const int default_state = 1;
|
||||
struct rfkill *rfkill;
|
||||
int ret;
|
||||
|
||||
dev_info(&pdev->dev, "starting\n");
|
||||
|
||||
s3c2410_gpio_cfgpin(GTA02_GPIO_nWLAN_RESET, S3C2410_GPIO_OUTPUT);
|
||||
gta02_wlan_reset(1);
|
||||
gta02_wlan_reset(0);
|
||||
|
||||
rfkill = rfkill_alloc("ar6000", &pdev->dev, RFKILL_TYPE_WLAN,
|
||||
>a02_wlan_rfkill_ops, &pdev->dev);
|
||||
|
||||
|
||||
if (!rfkill) {
|
||||
dev_err(&pdev->dev, "Failed to allocate rfkill\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rfkill_init_sw_state(rfkill, default_state);
|
||||
/*
|
||||
* If the WLAN driver somehow managed to get activated before we're
|
||||
* ready, the driver is now in an unknown state, which isn't something
|
||||
* we're prepared to handle. This can't happen, so just fail hard.
|
||||
*/
|
||||
BUG_ON(gta02_wlan_rfkill_cb);
|
||||
gta02_wlan_rfkill_on = default_state;
|
||||
|
||||
ret = rfkill_register(rfkill);
|
||||
if (ret) {
|
||||
rfkill_destroy(rfkill);
|
||||
dev_err(&pdev->dev, "Failed to register rfkill\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, rfkill);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gta02_wlan_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rfkill *rfkill = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
rfkill_destroy(rfkill);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gta02_wlan_driver = {
|
||||
.probe = gta02_wlan_probe,
|
||||
.remove = gta02_wlan_remove,
|
||||
.driver = {
|
||||
.name = "gta02-pm-wlan",
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit gta02_wlan_init(void)
|
||||
{
|
||||
return platform_driver_register(>a02_wlan_driver);
|
||||
}
|
||||
|
||||
static void gta02_wlan_exit(void)
|
||||
{
|
||||
platform_driver_unregister(>a02_wlan_driver);
|
||||
}
|
||||
|
||||
module_init(gta02_wlan_init);
|
||||
module_exit(gta02_wlan_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Andy Green <andy@openmoko.com>");
|
||||
MODULE_DESCRIPTION("Openmoko GTA02 WLAN power management");
|
|
@ -0,0 +1 @@
|
|||
extern int gta02_pm_gps_is_on(void);
|
|
@ -0,0 +1 @@
|
|||
extern int gta_gsm_interrupts;
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef __MACH_GTA02_PM_WLAN_H
|
||||
#define __MACH_GTA02_PM_WLAN_H
|
||||
|
||||
void gta02_wlan_reset(int assert_reset);
|
||||
int gta02_wlan_query_rfkill_lock(void);
|
||||
void gta02_wlan_query_rfkill_unlock(void);
|
||||
void gta02_wlan_set_rfkill_cb(int (*cb)(void *user, int on), void *user);
|
||||
void gta02_wlan_clear_rfkill_cb(void);
|
||||
|
||||
#endif /* __MACH_GTA02_PM_WLAN_H */
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef _GTA02_H
|
||||
#define _GTA02_H
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/regs-gpioj.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
/* Different hardware revisions, passed in ATAG_REVISION by u-boot */
|
||||
#define GTA02v1_SYSTEM_REV 0x00000310
|
||||
#define GTA02v2_SYSTEM_REV 0x00000320
|
||||
#define GTA02v3_SYSTEM_REV 0x00000330
|
||||
#define GTA02v4_SYSTEM_REV 0x00000340
|
||||
#define GTA02v5_SYSTEM_REV 0x00000350
|
||||
#define GTA02v6_SYSTEM_REV 0x00000360
|
||||
|
||||
#define GTA02_GPIO_n3DL_GSM S3C2410_GPA(13) /* v1 + v2 + v3 only */
|
||||
|
||||
#define GTA02_GPIO_PWR_LED1 S3C2410_GPB(0)
|
||||
#define GTA02_GPIO_PWR_LED2 S3C2410_GPB(1)
|
||||
#define GTA02_GPIO_AUX_LED S3C2410_GPB(2)
|
||||
#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB(3)
|
||||
#define GTA02_GPIO_MODEM_RST S3C2410_GPB(5)
|
||||
#define GTA02_GPIO_BT_EN S3C2410_GPB(6)
|
||||
#define GTA02_GPIO_MODEM_ON S3C2410_GPB(7)
|
||||
#define GTA02_GPIO_EXTINT8 S3C2410_GPB(8)
|
||||
#define GTA02_GPIO_USB_PULLUP S3C2410_GPB(9)
|
||||
|
||||
#define GTA02_GPIO_PIO5 S3C2410_GPC(5) /* v3 + v4 only */
|
||||
#define GTA02v3_GPIO_nG1_CS S3C2410_GPD(12) /* v3 + v4 only */
|
||||
#define GTA02v3_GPIO_nG2_CS S3C2410_GPD(13) /* v3 + v4 only */
|
||||
#define GTA02v5_GPIO_HDQ S3C2410_GPD(14) /* v5 + */
|
||||
|
||||
#define GTA02_GPIO_nG1_INT S3C2410_GPF(0)
|
||||
#define GTA02_GPIO_IO1 S3C2410_GPF(1)
|
||||
#define GTA02_GPIO_PIO_2 S3C2410_GPF(2) /* v2 + v3 + v4 only */
|
||||
#define GTA02_GPIO_JACK_INSERT S3C2410_GPF(4)
|
||||
#define GTA02_GPIO_WLAN_GPIO1 S3C2410_GPF(5) /* v2 + v3 + v4 only */
|
||||
#define GTA02_GPIO_AUX_KEY S3C2410_GPF(6)
|
||||
#define GTA02_GPIO_HOLD_KEY S3C2410_GPF(7)
|
||||
|
||||
#define GTA02_GPIO_3D_IRQ S3C2410_GPG(4)
|
||||
#define GTA02v2_GPIO_nG2_INT S3C2410_GPG(8) /* v2 + v3 + v4 only */
|
||||
#define GTA02v3_GPIO_nUSB_OC S3C2410_GPG(9) /* v3 + v4 only */
|
||||
#define GTA02v3_GPIO_nUSB_FLT S3C2410_GPG(10) /* v3 + v4 only */
|
||||
#define GTA02v3_GPIO_nGSM_OC S3C2410_GPG(11) /* v3 + v4 only */
|
||||
|
||||
#define GTA02_GPIO_AMP_SHUT S3C2440_GPJ1 /* v2 + v3 + v4 only */
|
||||
#define GTA02v1_GPIO_WLAN_GPIO10 S3C2440_GPJ2
|
||||
#define GTA02_GPIO_HP_IN S3C2440_GPJ2 /* v2 + v3 + v4 only */
|
||||
#define GTA02_GPIO_INT0 S3C2440_GPJ3 /* v2 + v3 + v4 only */
|
||||
#define GTA02_GPIO_nGSM_EN S3C2440_GPJ4
|
||||
#define GTA02_GPIO_3D_RESET S3C2440_GPJ5
|
||||
#define GTA02_GPIO_nDL_GSM S3C2440_GPJ6 /* v4 + v5 only */
|
||||
#define GTA02_GPIO_WLAN_GPIO0 S3C2440_GPJ7
|
||||
#define GTA02v1_GPIO_BAT_ID S3C2440_GPJ8
|
||||
#define GTA02_GPIO_KEEPACT S3C2440_GPJ8
|
||||
#define GTA02v1_GPIO_HP_IN S3C2440_GPJ10
|
||||
#define GTA02_CHIP_PWD S3C2440_GPJ11 /* v2 + v3 + v4 only */
|
||||
#define GTA02_GPIO_nWLAN_RESET S3C2440_GPJ12 /* v2 + v3 + v4 only */
|
||||
|
||||
#define GTA02_IRQ_GSENSOR_1 IRQ_EINT0
|
||||
#define GTA02_IRQ_MODEM IRQ_EINT1
|
||||
#define GTA02_IRQ_PIO_2 IRQ_EINT2 /* v2 + v3 + v4 only */
|
||||
#define GTA02_IRQ_nJACK_INSERT IRQ_EINT4
|
||||
#define GTA02_IRQ_WLAN_GPIO1 IRQ_EINT5
|
||||
#define GTA02_IRQ_AUX IRQ_EINT6
|
||||
#define GTA02_IRQ_nHOLD IRQ_EINT7
|
||||
#define GTA02_IRQ_PCF50633 IRQ_EINT9
|
||||
#define GTA02_IRQ_3D IRQ_EINT12
|
||||
#define GTA02_IRQ_GSENSOR_2 IRQ_EINT16 /* v2 + v3 + v4 only */
|
||||
#define GTA02v3_IRQ_nUSB_OC IRQ_EINT17 /* v3 + v4 only */
|
||||
#define GTA02v3_IRQ_nUSB_FLT IRQ_EINT18 /* v3 + v4 only */
|
||||
#define GTA02v3_IRQ_nGSM_OC IRQ_EINT19 /* v3 + v4 only */
|
||||
|
||||
/* returns 00 000 on GTA02 A5 and earlier, A6 returns 01 001 */
|
||||
#define GTA02_PCB_ID1_0 S3C2410_GPC(13)
|
||||
#define GTA02_PCB_ID1_1 S3C2410_GPC(15)
|
||||
#define GTA02_PCB_ID1_2 S3C2410_GPD(0)
|
||||
#define GTA02_PCB_ID2_0 S3C2410_GPD(3)
|
||||
#define GTA02_PCB_ID2_1 S3C2410_GPD(4)
|
||||
|
||||
#define GTA02_GPIO_GLAMO_BASE S3C_GPIO_END
|
||||
#define GTA02_GPIO_GLAMO(x) (GTA02_GPIO_GLAMO_BASE + x)
|
||||
|
||||
int gta02_get_pcb_revision(void);
|
||||
|
||||
extern struct pcf50633 *gta02_pcf;
|
||||
|
||||
#endif /* _GTA02_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
|||
config AR6000_WLAN
|
||||
tristate "AR6000 wireless networking over SDIO"
|
||||
depends on MMC
|
||||
select WIRELESS_EXT
|
||||
default m
|
||||
help
|
||||
good luck.
|
||||
|
||||
config AR6000_WLAN_DEBUG
|
||||
bool "Enable retrieval of firmware debugging information"
|
||||
depends on AR6000_WLAN
|
||||
default n
|
||||
help
|
||||
The AR6k firmware maintains a log of debugging events that
|
||||
gets flushed to the host on various occasions. Retrieval of
|
||||
this data is very slow, taking several seconds.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config AR6000_WLAN_RESET
|
||||
bool "Soft-reset when shutting down"
|
||||
depends on AR6000_WLAN
|
||||
default n
|
||||
help
|
||||
The AR6k module can be explicitly reset when shutting down
|
||||
the device. This adds a delay of about two seconds to suspend,
|
||||
module removal, and so on. Since the WLAN SDIO function is
|
||||
generally disabled soon thereafter anyway, this reset seems
|
||||
superfluous.
|
||||
|
||||
If in doubt, say N.
|
|
@ -0,0 +1,38 @@
|
|||
REV ?= 2
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
EXTRA_CFLAGS += -I$(src)/include
|
||||
|
||||
EXTRA_CFLAGS += -DLINUX -D__KERNEL__ -DHTC_RAW_INTERFACE\
|
||||
-DTCMD -DUSER_KEYS \
|
||||
-DNO_SYNC_FLUSH #\
|
||||
-DMULTIPLE_FRAMES_PER_INTERRUPT -DAR6000REV$(REV) \
|
||||
-DBLOCK_TX_PATH_FLAG \
|
||||
-DSDIO \
|
||||
|
||||
EXTRA_CFLAGS += -DKERNEL_2_6
|
||||
|
||||
obj-$(CONFIG_AR6000_WLAN) += ar6000.o
|
||||
|
||||
ar6000-objs += htc/ar6k.o \
|
||||
htc/ar6k_events.o \
|
||||
htc/htc_send.o \
|
||||
htc/htc_recv.o \
|
||||
htc/htc_services.o \
|
||||
htc/htc.o \
|
||||
hif/hif2.o \
|
||||
bmi/bmi.o \
|
||||
ar6000/ar6000_drv.o \
|
||||
ar6000/ar6000_raw_if.o \
|
||||
ar6000/netbuf.o \
|
||||
ar6000/wireless_ext.o \
|
||||
ar6000/ioctl.o \
|
||||
miscdrv/common_drv.o \
|
||||
miscdrv/credit_dist.o \
|
||||
wmi/wmi.o \
|
||||
wlan/wlan_node.o \
|
||||
wlan/wlan_recv_beacon.o \
|
||||
wlan/wlan_utils.o
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AR6000_H_
|
||||
#define _AR6000_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <a_config.h>
|
||||
#include <athdefs.h>
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "htc_api.h"
|
||||
#include "wmi.h"
|
||||
#include "a_drv.h"
|
||||
#include "bmi.h"
|
||||
#include <ieee80211.h>
|
||||
#include <ieee80211_ioctl.h>
|
||||
#include <wlan_api.h>
|
||||
#include <wmi_api.h>
|
||||
#include "gpio_api.h"
|
||||
#include "gpio.h"
|
||||
#include <host_version.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include "AR6Khwreg.h"
|
||||
#include "ar6000_api.h"
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
#include <testcmd.h>
|
||||
#endif
|
||||
|
||||
#include "targaddrs.h"
|
||||
#include "dbglog_api.h"
|
||||
#include "ar6000_diag.h"
|
||||
#include "common_drv.h"
|
||||
|
||||
#ifndef __dev_put
|
||||
#define __dev_put(dev) dev_put(dev)
|
||||
#endif
|
||||
|
||||
#ifdef USER_KEYS
|
||||
|
||||
#define USER_SAVEDKEYS_STAT_INIT 0
|
||||
#define USER_SAVEDKEYS_STAT_RUN 1
|
||||
|
||||
// TODO this needs to move into the AR_SOFTC struct
|
||||
struct USER_SAVEDKEYS {
|
||||
struct ieee80211req_key ucast_ik;
|
||||
struct ieee80211req_key bcast_ik;
|
||||
CRYPTO_TYPE keyType;
|
||||
A_BOOL keyOk;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define DBG_INFO 0x00000001
|
||||
#define DBG_ERROR 0x00000002
|
||||
#define DBG_WARNING 0x00000004
|
||||
#define DBG_SDIO 0x00000008
|
||||
#define DBG_HIF 0x00000010
|
||||
#define DBG_HTC 0x00000020
|
||||
#define DBG_WMI 0x00000040
|
||||
#define DBG_WMI2 0x00000080
|
||||
#define DBG_DRIVER 0x00000100
|
||||
|
||||
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#define AR_DEBUG_PRINTF(args...) if (debugdriver) A_PRINTF(args);
|
||||
#define AR_DEBUG2_PRINTF(args...) if (debugdriver >= 2) A_PRINTF(args);
|
||||
extern int debugdriver;
|
||||
#else
|
||||
#define AR_DEBUG_PRINTF(args...)
|
||||
#define AR_DEBUG2_PRINTF(args...)
|
||||
#endif
|
||||
|
||||
A_STATUS ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
A_STATUS ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_AR6000 1
|
||||
#define AR6000_MAX_RX_BUFFERS 16
|
||||
#define AR6000_BUFFER_SIZE 1664
|
||||
#define AR6000_TX_TIMEOUT 10
|
||||
#define AR6000_ETH_ADDR_LEN 6
|
||||
#define AR6000_MAX_ENDPOINTS 4
|
||||
#define MAX_NODE_NUM 15
|
||||
#define MAX_COOKIE_NUM 150
|
||||
#define AR6000_HB_CHALLENGE_RESP_FREQ_DEFAULT 1
|
||||
#define AR6000_HB_CHALLENGE_RESP_MISS_THRES_DEFAULT 1
|
||||
|
||||
enum {
|
||||
DRV_HB_CHALLENGE = 0,
|
||||
APP_HB_CHALLENGE
|
||||
};
|
||||
|
||||
/* HTC RAW streams */
|
||||
typedef enum _HTC_RAW_STREAM_ID {
|
||||
HTC_RAW_STREAM_NOT_MAPPED = -1,
|
||||
HTC_RAW_STREAM_0 = 0,
|
||||
HTC_RAW_STREAM_1 = 1,
|
||||
HTC_RAW_STREAM_2 = 2,
|
||||
HTC_RAW_STREAM_3 = 3,
|
||||
HTC_RAW_STREAM_NUM_MAX
|
||||
} HTC_RAW_STREAM_ID;
|
||||
|
||||
#define RAW_HTC_READ_BUFFERS_NUM 4
|
||||
#define RAW_HTC_WRITE_BUFFERS_NUM 4
|
||||
|
||||
typedef struct {
|
||||
int currPtr;
|
||||
int length;
|
||||
unsigned char data[AR6000_BUFFER_SIZE];
|
||||
HTC_PACKET HTCPacket;
|
||||
} raw_htc_buffer;
|
||||
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
/*
|
||||
* add TCMD_MODE besides wmi and bypasswmi
|
||||
* in TCMD_MODE, only few TCMD releated wmi commands
|
||||
* counld be hanlder
|
||||
*/
|
||||
enum {
|
||||
AR6000_WMI_MODE = 0,
|
||||
AR6000_BYPASS_MODE,
|
||||
AR6000_TCMD_MODE,
|
||||
AR6000_WLAN_MODE
|
||||
};
|
||||
#endif /* CONFIG_HOST_TCMD_SUPPORT */
|
||||
|
||||
struct ar_wep_key {
|
||||
A_UINT8 arKeyIndex;
|
||||
A_UINT8 arKeyLen;
|
||||
A_UINT8 arKey[64];
|
||||
} ;
|
||||
|
||||
struct ar_node_mapping {
|
||||
A_UINT8 macAddress[6];
|
||||
A_UINT8 epId;
|
||||
A_UINT8 txPending;
|
||||
};
|
||||
|
||||
struct ar_cookie {
|
||||
A_UINT32 arc_bp[2]; /* Must be first field */
|
||||
HTC_PACKET HtcPkt; /* HTC packet wrapper */
|
||||
struct ar_cookie *arc_list_next;
|
||||
};
|
||||
|
||||
struct ar_hb_chlng_resp {
|
||||
A_TIMER timer;
|
||||
A_UINT32 frequency;
|
||||
A_UINT32 seqNum;
|
||||
A_BOOL outstanding;
|
||||
A_UINT8 missCnt;
|
||||
A_UINT8 missThres;
|
||||
};
|
||||
|
||||
typedef struct ar6_softc {
|
||||
struct net_device *arNetDev; /* net_device pointer */
|
||||
void *arWmi;
|
||||
int arTxPending[WMI_PRI_MAX_COUNT];
|
||||
int arTotalTxDataPending;
|
||||
A_UINT8 arNumDataEndPts;
|
||||
A_BOOL arWmiEnabled;
|
||||
A_BOOL arWmiReady;
|
||||
A_BOOL arConnected;
|
||||
A_BOOL arRadioSwitch;
|
||||
HTC_HANDLE arHtcTarget;
|
||||
void *arHifDevice;
|
||||
spinlock_t arLock;
|
||||
struct semaphore arSem;
|
||||
int arRxBuffers[WMI_PRI_MAX_COUNT];
|
||||
int arSsidLen;
|
||||
u_char arSsid[32];
|
||||
A_UINT8 arNetworkType;
|
||||
A_UINT8 arDot11AuthMode;
|
||||
A_UINT8 arAuthMode;
|
||||
A_UINT8 arPairwiseCrypto;
|
||||
A_UINT8 arPairwiseCryptoLen;
|
||||
A_UINT8 arGroupCrypto;
|
||||
A_UINT8 arGroupCryptoLen;
|
||||
A_UINT8 arDefTxKeyIndex;
|
||||
struct ar_wep_key arWepKeyList[WMI_MAX_KEY_INDEX + 1];
|
||||
A_UINT8 arBssid[6];
|
||||
A_UINT8 arReqBssid[6];
|
||||
A_UINT16 arChannelHint;
|
||||
A_UINT16 arBssChannel;
|
||||
A_UINT16 arListenInterval;
|
||||
struct ar6000_version arVersion;
|
||||
A_UINT32 arTargetType;
|
||||
A_INT8 arRssi;
|
||||
A_UINT8 arTxPwr;
|
||||
A_BOOL arTxPwrSet;
|
||||
A_INT32 arBitRate;
|
||||
struct net_device_stats arNetStats;
|
||||
struct iw_statistics arIwStats;
|
||||
A_INT8 arNumChannels;
|
||||
A_UINT16 arChannelList[32];
|
||||
A_UINT32 arRegCode;
|
||||
A_BOOL statsUpdatePending;
|
||||
TARGET_STATS arTargetStats;
|
||||
A_INT8 arMaxRetries;
|
||||
A_UINT8 arPhyCapability;
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
A_UINT8 tcmdRxReport;
|
||||
A_UINT32 tcmdRxTotalPkt;
|
||||
A_INT32 tcmdRxRssi;
|
||||
A_UINT32 tcmdPm;
|
||||
A_UINT32 arTargetMode;
|
||||
#endif
|
||||
AR6000_WLAN_STATE arWlanState;
|
||||
struct ar_node_mapping arNodeMap[MAX_NODE_NUM];
|
||||
A_UINT8 arIbssPsEnable;
|
||||
A_UINT8 arNodeNum;
|
||||
A_UINT8 arNexEpId;
|
||||
struct ar_cookie *arCookieList;
|
||||
A_UINT16 arRateMask;
|
||||
A_UINT8 arSkipScan;
|
||||
A_UINT16 arBeaconInterval;
|
||||
A_BOOL arConnectPending;
|
||||
A_BOOL arWmmEnabled;
|
||||
struct ar_hb_chlng_resp arHBChallengeResp;
|
||||
A_UINT8 arKeepaliveConfigured;
|
||||
A_UINT32 arMgmtFilter;
|
||||
HTC_ENDPOINT_ID arWmi2EpMapping[WMI_PRI_MAX_COUNT];
|
||||
WMI_PRI_STREAM_ID arEp2WmiMapping[ENDPOINT_MAX];
|
||||
#ifdef HTC_RAW_INTERFACE
|
||||
HTC_ENDPOINT_ID arRaw2EpMapping[HTC_RAW_STREAM_NUM_MAX];
|
||||
HTC_RAW_STREAM_ID arEp2RawMapping[ENDPOINT_MAX];
|
||||
struct semaphore raw_htc_read_sem[HTC_RAW_STREAM_NUM_MAX];
|
||||
struct semaphore raw_htc_write_sem[HTC_RAW_STREAM_NUM_MAX];
|
||||
wait_queue_head_t raw_htc_read_queue[HTC_RAW_STREAM_NUM_MAX];
|
||||
wait_queue_head_t raw_htc_write_queue[HTC_RAW_STREAM_NUM_MAX];
|
||||
raw_htc_buffer *raw_htc_read_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_READ_BUFFERS_NUM];
|
||||
raw_htc_buffer *raw_htc_write_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_WRITE_BUFFERS_NUM];
|
||||
A_BOOL write_buffer_available[HTC_RAW_STREAM_NUM_MAX];
|
||||
A_BOOL read_buffer_available[HTC_RAW_STREAM_NUM_MAX];
|
||||
#endif
|
||||
A_BOOL arRawIfInit;
|
||||
int arDeviceIndex;
|
||||
COMMON_CREDIT_STATE_INFO arCreditStateInfo;
|
||||
A_BOOL arWMIControlEpFull;
|
||||
A_BOOL dbgLogFetchInProgress;
|
||||
A_UCHAR log_buffer[DBGLOG_HOST_LOG_BUFFER_SIZE];
|
||||
A_UINT32 log_cnt;
|
||||
A_UINT32 dbglog_init_done;
|
||||
A_UINT32 arConnectCtrlFlags;
|
||||
A_UINT32 scan_complete;
|
||||
#ifdef USER_KEYS
|
||||
A_INT32 user_savedkeys_stat;
|
||||
A_UINT32 user_key_ctrl;
|
||||
struct USER_SAVEDKEYS user_saved_keys;
|
||||
#endif
|
||||
} AR_SOFTC_T;
|
||||
|
||||
|
||||
#define arWMIStream2EndpointID(ar,wmi) (ar)->arWmi2EpMapping[(wmi)]
|
||||
#define arSetWMIStream2EndpointIDMap(ar,wmi,ep) \
|
||||
{ (ar)->arWmi2EpMapping[(wmi)] = (ep); \
|
||||
(ar)->arEp2WmiMapping[(ep)] = (wmi); }
|
||||
#define arEndpoint2WMIStreamID(ar,ep) (ar)->arEp2WmiMapping[(ep)]
|
||||
|
||||
#define arRawIfEnabled(ar) (ar)->arRawIfInit
|
||||
#define arRawStream2EndpointID(ar,raw) (ar)->arRaw2EpMapping[(raw)]
|
||||
#define arSetRawStream2EndpointIDMap(ar,raw,ep) \
|
||||
{ (ar)->arRaw2EpMapping[(raw)] = (ep); \
|
||||
(ar)->arEp2RawMapping[(ep)] = (raw); }
|
||||
#define arEndpoint2RawStreamID(ar,ep) (ar)->arEp2RawMapping[(ep)]
|
||||
|
||||
struct ar_giwscan_param {
|
||||
char *current_ev;
|
||||
char *end_buf;
|
||||
A_BOOL firstPass;
|
||||
};
|
||||
|
||||
#define AR6000_STAT_INC(ar, stat) (ar->arNetStats.stat++)
|
||||
|
||||
#define AR6000_SPIN_LOCK(lock, param) do { \
|
||||
if (irqs_disabled()) { \
|
||||
AR_DEBUG_PRINTF("IRQs disabled:AR6000_LOCK\n"); \
|
||||
} \
|
||||
spin_lock_bh(lock); \
|
||||
} while (0)
|
||||
|
||||
#define AR6000_SPIN_UNLOCK(lock, param) do { \
|
||||
if (irqs_disabled()) { \
|
||||
AR_DEBUG_PRINTF("IRQs disabled: AR6000_UNLOCK\n"); \
|
||||
} \
|
||||
spin_unlock_bh(lock); \
|
||||
} while (0)
|
||||
|
||||
int ar6000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
int ar6000_ioctl_dispatcher(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
void ar6000_ioctl_iwsetup(struct iw_handler_def *def);
|
||||
void ar6000_gpio_init(void);
|
||||
void ar6000_init_profile_info(AR_SOFTC_T *ar);
|
||||
void ar6000_install_static_wep_keys(AR_SOFTC_T *ar);
|
||||
int ar6000_init(struct net_device *dev);
|
||||
int ar6000_dbglog_get_debug_logs(AR_SOFTC_T *ar);
|
||||
A_STATUS ar6000_SetHTCBlockSize(AR_SOFTC_T *ar);
|
||||
|
||||
#ifdef HTC_RAW_INTERFACE
|
||||
|
||||
#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
int ar6000_htc_raw_open(AR_SOFTC_T *ar);
|
||||
int ar6000_htc_raw_close(AR_SOFTC_T *ar);
|
||||
ssize_t ar6000_htc_raw_read(AR_SOFTC_T *ar,
|
||||
HTC_RAW_STREAM_ID StreamID,
|
||||
char __user *buffer, size_t count);
|
||||
ssize_t ar6000_htc_raw_write(AR_SOFTC_T *ar,
|
||||
HTC_RAW_STREAM_ID StreamID,
|
||||
char __user *buffer, size_t count);
|
||||
|
||||
#endif /* HTC_RAW_INTERFACE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AR6000_H_ */
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ar6000_drv.h"
|
||||
|
||||
#ifdef HTC_RAW_INTERFACE
|
||||
|
||||
static void
|
||||
ar6000_htc_raw_read_cb(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
|
||||
raw_htc_buffer *busy;
|
||||
HTC_RAW_STREAM_ID streamID;
|
||||
|
||||
busy = (raw_htc_buffer *)pPacket->pPktContext;
|
||||
A_ASSERT(busy != NULL);
|
||||
|
||||
if (pPacket->Status == A_ECANCELED) {
|
||||
/*
|
||||
* HTC provides A_ECANCELED status when it doesn't want to be refilled
|
||||
* (probably due to a shutdown)
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
|
||||
A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
|
||||
|
||||
#ifdef CF
|
||||
if (down_trylock(&ar->raw_htc_read_sem[streamID])) {
|
||||
#else
|
||||
if (down_interruptible(&ar->raw_htc_read_sem[streamID])) {
|
||||
#endif /* CF */
|
||||
AR_DEBUG2_PRINTF("Unable to down the semaphore\n");
|
||||
}
|
||||
|
||||
A_ASSERT((pPacket->Status != A_OK) ||
|
||||
(pPacket->pBuffer == (busy->data + HTC_HEADER_LEN)));
|
||||
|
||||
busy->length = pPacket->ActualLength + HTC_HEADER_LEN;
|
||||
busy->currPtr = HTC_HEADER_LEN;
|
||||
ar->read_buffer_available[streamID] = TRUE;
|
||||
//AR_DEBUG_PRINTF("raw read cb: 0x%X 0x%X \n", busy->currPtr,busy->length);
|
||||
up(&ar->raw_htc_read_sem[streamID]);
|
||||
|
||||
/* Signal the waiting process */
|
||||
AR_DEBUG2_PRINTF("Waking up the StreamID(%d) read process\n", streamID);
|
||||
wake_up_interruptible(&ar->raw_htc_read_queue[streamID]);
|
||||
}
|
||||
|
||||
static void
|
||||
ar6000_htc_raw_write_cb(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
|
||||
raw_htc_buffer *free;
|
||||
HTC_RAW_STREAM_ID streamID;
|
||||
|
||||
free = (raw_htc_buffer *)pPacket->pPktContext;
|
||||
A_ASSERT(free != NULL);
|
||||
|
||||
if (pPacket->Status == A_ECANCELED) {
|
||||
/*
|
||||
* HTC provides A_ECANCELED status when it doesn't want to be refilled
|
||||
* (probably due to a shutdown)
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
|
||||
A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
|
||||
|
||||
#ifdef CF
|
||||
if (down_trylock(&ar->raw_htc_write_sem[streamID])) {
|
||||
#else
|
||||
if (down_interruptible(&ar->raw_htc_write_sem[streamID])) {
|
||||
#endif
|
||||
AR_DEBUG2_PRINTF("Unable to down the semaphore\n");
|
||||
}
|
||||
|
||||
A_ASSERT(pPacket->pBuffer == (free->data + HTC_HEADER_LEN));
|
||||
|
||||
free->length = 0;
|
||||
ar->write_buffer_available[streamID] = TRUE;
|
||||
up(&ar->raw_htc_write_sem[streamID]);
|
||||
|
||||
/* Signal the waiting process */
|
||||
AR_DEBUG2_PRINTF("Waking up the StreamID(%d) write process\n", streamID);
|
||||
wake_up_interruptible(&ar->raw_htc_write_queue[streamID]);
|
||||
}
|
||||
|
||||
/* connect to a service */
|
||||
static A_STATUS ar6000_connect_raw_service(AR_SOFTC_T *ar,
|
||||
HTC_RAW_STREAM_ID StreamID)
|
||||
{
|
||||
A_STATUS status;
|
||||
HTC_SERVICE_CONNECT_RESP response;
|
||||
A_UINT8 streamNo;
|
||||
HTC_SERVICE_CONNECT_REQ connect;
|
||||
|
||||
do {
|
||||
|
||||
A_MEMZERO(&connect,sizeof(connect));
|
||||
/* pass the stream ID as meta data to the RAW streams service */
|
||||
streamNo = (A_UINT8)StreamID;
|
||||
connect.pMetaData = &streamNo;
|
||||
connect.MetaDataLength = sizeof(A_UINT8);
|
||||
/* these fields are the same for all endpoints */
|
||||
connect.EpCallbacks.pContext = ar;
|
||||
connect.EpCallbacks.EpTxComplete = ar6000_htc_raw_write_cb;
|
||||
connect.EpCallbacks.EpRecv = ar6000_htc_raw_read_cb;
|
||||
/* simple interface, we don't need these optional callbacks */
|
||||
connect.EpCallbacks.EpRecvRefill = NULL;
|
||||
connect.EpCallbacks.EpSendFull = NULL;
|
||||
connect.EpCallbacks.EpSendAvail = NULL;
|
||||
connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM;
|
||||
|
||||
/* connect to the raw streams service, we may be able to get 1 or more
|
||||
* connections, depending on WHAT is running on the target */
|
||||
connect.ServiceID = HTC_RAW_STREAMS_SVC;
|
||||
|
||||
A_MEMZERO(&response,sizeof(response));
|
||||
|
||||
/* try to connect to the raw stream, it is okay if this fails with
|
||||
* status HTC_SERVICE_NO_MORE_EP */
|
||||
status = HTCConnectService(ar->arHtcTarget,
|
||||
&connect,
|
||||
&response);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
if (response.ConnectRespCode == HTC_SERVICE_NO_MORE_EP) {
|
||||
AR_DEBUG_PRINTF("HTC RAW , No more streams allowed \n");
|
||||
status = A_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* set endpoint mapping for the RAW HTC streams */
|
||||
arSetRawStream2EndpointIDMap(ar,StreamID,response.Endpoint);
|
||||
|
||||
AR_DEBUG_PRINTF("HTC RAW : stream ID: %d, endpoint: %d\n",
|
||||
StreamID, arRawStream2EndpointID(ar,StreamID));
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ar6000_htc_raw_open(AR_SOFTC_T *ar)
|
||||
{
|
||||
A_STATUS status;
|
||||
int streamID, endPt, count2;
|
||||
raw_htc_buffer *buffer;
|
||||
HTC_SERVICE_ID servicepriority;
|
||||
|
||||
A_ASSERT(ar->arHtcTarget != NULL);
|
||||
|
||||
/* wait for target */
|
||||
status = HTCWaitTarget(ar->arHtcTarget);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF("HTCWaitTarget failed (%d)\n", status);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (endPt = 0; endPt < ENDPOINT_MAX; endPt++) {
|
||||
ar->arEp2RawMapping[endPt] = HTC_RAW_STREAM_NOT_MAPPED;
|
||||
}
|
||||
|
||||
for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
|
||||
/* Initialize the data structures */
|
||||
init_MUTEX(&ar->raw_htc_read_sem[streamID]);
|
||||
init_MUTEX(&ar->raw_htc_write_sem[streamID]);
|
||||
init_waitqueue_head(&ar->raw_htc_read_queue[streamID]);
|
||||
init_waitqueue_head(&ar->raw_htc_write_queue[streamID]);
|
||||
|
||||
/* try to connect to the raw service */
|
||||
status = ar6000_connect_raw_service(ar,streamID);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (arRawStream2EndpointID(ar,streamID) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (count2 = 0; count2 < RAW_HTC_READ_BUFFERS_NUM; count2 ++) {
|
||||
/* Initialize the receive buffers */
|
||||
buffer = ar->raw_htc_write_buffer[streamID][count2];
|
||||
memset(buffer, 0, sizeof(raw_htc_buffer));
|
||||
buffer = ar->raw_htc_read_buffer[streamID][count2];
|
||||
memset(buffer, 0, sizeof(raw_htc_buffer));
|
||||
|
||||
SET_HTC_PACKET_INFO_RX_REFILL(&buffer->HTCPacket,
|
||||
buffer,
|
||||
buffer->data,
|
||||
AR6000_BUFFER_SIZE,
|
||||
arRawStream2EndpointID(ar,streamID));
|
||||
|
||||
/* Queue buffers to HTC for receive */
|
||||
if ((status = HTCAddReceivePkt(ar->arHtcTarget, &buffer->HTCPacket)) != A_OK)
|
||||
{
|
||||
BMIInit();
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
for (count2 = 0; count2 < RAW_HTC_WRITE_BUFFERS_NUM; count2 ++) {
|
||||
/* Initialize the receive buffers */
|
||||
buffer = ar->raw_htc_write_buffer[streamID][count2];
|
||||
memset(buffer, 0, sizeof(raw_htc_buffer));
|
||||
}
|
||||
|
||||
ar->read_buffer_available[streamID] = FALSE;
|
||||
ar->write_buffer_available[streamID] = TRUE;
|
||||
}
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF("HTC RAW, number of streams the target supports: %d \n", streamID);
|
||||
|
||||
servicepriority = HTC_RAW_STREAMS_SVC; /* only 1 */
|
||||
|
||||
/* set callbacks and priority list */
|
||||
HTCSetCreditDistribution(ar->arHtcTarget,
|
||||
ar,
|
||||
NULL, /* use default */
|
||||
NULL, /* use default */
|
||||
&servicepriority,
|
||||
1);
|
||||
|
||||
/* Start the HTC component */
|
||||
if ((status = HTCStart(ar->arHtcTarget)) != A_OK) {
|
||||
BMIInit();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
(ar)->arRawIfInit = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ar6000_htc_raw_close(AR_SOFTC_T *ar)
|
||||
{
|
||||
A_PRINTF("ar6000_htc_raw_close called \n");
|
||||
HTCStop(ar->arHtcTarget);
|
||||
|
||||
/* reset the device */
|
||||
ar6000_reset_device(ar->arHifDevice, ar->arTargetType);
|
||||
/* Initialize the BMI component */
|
||||
BMIInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
raw_htc_buffer *
|
||||
get_filled_buffer(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID)
|
||||
{
|
||||
int count;
|
||||
raw_htc_buffer *busy;
|
||||
|
||||
/* Check for data */
|
||||
for (count = 0; count < RAW_HTC_READ_BUFFERS_NUM; count ++) {
|
||||
busy = ar->raw_htc_read_buffer[StreamID][count];
|
||||
if (busy->length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (busy->length) {
|
||||
ar->read_buffer_available[StreamID] = TRUE;
|
||||
} else {
|
||||
ar->read_buffer_available[StreamID] = FALSE;
|
||||
}
|
||||
|
||||
return busy;
|
||||
}
|
||||
|
||||
ssize_t ar6000_htc_raw_read(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID,
|
||||
char __user *buffer, size_t length)
|
||||
{
|
||||
int readPtr;
|
||||
raw_htc_buffer *busy;
|
||||
|
||||
if (arRawStream2EndpointID(ar,StreamID) == 0) {
|
||||
AR_DEBUG_PRINTF("StreamID(%d) not connected! \n", StreamID);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (down_interruptible(&ar->raw_htc_read_sem[StreamID])) {
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
busy = get_filled_buffer(ar,StreamID);
|
||||
while (!ar->read_buffer_available[StreamID]) {
|
||||
up(&ar->raw_htc_read_sem[StreamID]);
|
||||
|
||||
/* Wait for the data */
|
||||
AR_DEBUG2_PRINTF("Sleeping StreamID(%d) read process\n", StreamID);
|
||||
if (wait_event_interruptible(ar->raw_htc_read_queue[StreamID],
|
||||
ar->read_buffer_available[StreamID]))
|
||||
{
|
||||
return -EINTR;
|
||||
}
|
||||
if (down_interruptible(&ar->raw_htc_read_sem[StreamID])) {
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
busy = get_filled_buffer(ar,StreamID);
|
||||
}
|
||||
|
||||
/* Read the data */
|
||||
readPtr = busy->currPtr;
|
||||
if (length > busy->length - HTC_HEADER_LEN) {
|
||||
length = busy->length - HTC_HEADER_LEN;
|
||||
}
|
||||
if (copy_to_user(buffer, &busy->data[readPtr], length)) {
|
||||
up(&ar->raw_htc_read_sem[StreamID]);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
busy->currPtr += length;
|
||||
|
||||
//AR_DEBUG_PRINTF("raw read ioctl: currPTR : 0x%X 0x%X \n", busy->currPtr,busy->length);
|
||||
|
||||
if (busy->currPtr == busy->length)
|
||||
{
|
||||
busy->currPtr = 0;
|
||||
busy->length = 0;
|
||||
HTC_PACKET_RESET_RX(&busy->HTCPacket);
|
||||
//AR_DEBUG_PRINTF("raw read ioctl: ep for packet:%d \n", busy->HTCPacket.Endpoint);
|
||||
HTCAddReceivePkt(ar->arHtcTarget, &busy->HTCPacket);
|
||||
}
|
||||
ar->read_buffer_available[StreamID] = FALSE;
|
||||
up(&ar->raw_htc_read_sem[StreamID]);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static raw_htc_buffer *
|
||||
get_free_buffer(AR_SOFTC_T *ar, HTC_ENDPOINT_ID StreamID)
|
||||
{
|
||||
int count;
|
||||
raw_htc_buffer *free;
|
||||
|
||||
free = NULL;
|
||||
for (count = 0; count < RAW_HTC_WRITE_BUFFERS_NUM; count ++) {
|
||||
free = ar->raw_htc_write_buffer[StreamID][count];
|
||||
if (free->length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!free->length) {
|
||||
ar->write_buffer_available[StreamID] = TRUE;
|
||||
} else {
|
||||
ar->write_buffer_available[StreamID] = FALSE;
|
||||
}
|
||||
|
||||
return free;
|
||||
}
|
||||
|
||||
ssize_t ar6000_htc_raw_write(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID,
|
||||
char __user *buffer, size_t length)
|
||||
{
|
||||
int writePtr;
|
||||
raw_htc_buffer *free;
|
||||
|
||||
if (arRawStream2EndpointID(ar,StreamID) == 0) {
|
||||
AR_DEBUG_PRINTF("StreamID(%d) not connected! \n", StreamID);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (down_interruptible(&ar->raw_htc_write_sem[StreamID])) {
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
/* Search for a free buffer */
|
||||
free = get_free_buffer(ar,StreamID);
|
||||
|
||||
/* Check if there is space to write else wait */
|
||||
while (!ar->write_buffer_available[StreamID]) {
|
||||
up(&ar->raw_htc_write_sem[StreamID]);
|
||||
|
||||
/* Wait for buffer to become free */
|
||||
AR_DEBUG2_PRINTF("Sleeping StreamID(%d) write process\n", StreamID);
|
||||
if (wait_event_interruptible(ar->raw_htc_write_queue[StreamID],
|
||||
ar->write_buffer_available[StreamID]))
|
||||
{
|
||||
return -EINTR;
|
||||
}
|
||||
if (down_interruptible(&ar->raw_htc_write_sem[StreamID])) {
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
free = get_free_buffer(ar,StreamID);
|
||||
}
|
||||
|
||||
/* Send the data */
|
||||
writePtr = HTC_HEADER_LEN;
|
||||
if (length > (AR6000_BUFFER_SIZE - HTC_HEADER_LEN)) {
|
||||
length = AR6000_BUFFER_SIZE - HTC_HEADER_LEN;
|
||||
}
|
||||
|
||||
if (copy_from_user(&free->data[writePtr], buffer, length)) {
|
||||
up(&ar->raw_htc_read_sem[StreamID]);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
free->length = length;
|
||||
|
||||
SET_HTC_PACKET_INFO_TX(&free->HTCPacket,
|
||||
free,
|
||||
&free->data[writePtr],
|
||||
length,
|
||||
arRawStream2EndpointID(ar,StreamID),
|
||||
AR6K_DATA_PKT_TAG);
|
||||
|
||||
HTCSendPkt(ar->arHtcTarget,&free->HTCPacket);
|
||||
|
||||
ar->write_buffer_available[StreamID] = FALSE;
|
||||
up(&ar->raw_htc_write_sem[StreamID]);
|
||||
|
||||
return length;
|
||||
}
|
||||
#endif /* HTC_RAW_INTERFACE */
|
|
@ -0,0 +1,128 @@
|
|||
#ifndef _AR6XAPI_LINUX_H
|
||||
#define _AR6XAPI_LINUX_H
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ar6_softc;
|
||||
|
||||
void ar6000_ready_event(void *devt, A_UINT8 *datap, A_UINT8 phyCap);
|
||||
A_UINT8 ar6000_iptos_to_userPriority(A_UINT8 *pkt);
|
||||
A_STATUS ar6000_control_tx(void *devt, void *osbuf, WMI_PRI_STREAM_ID streamID);
|
||||
void ar6000_connect_event(struct ar6_softc *ar, A_UINT16 channel,
|
||||
A_UINT8 *bssid, A_UINT16 listenInterval,
|
||||
A_UINT16 beaconInterval, NETWORK_TYPE networkType,
|
||||
A_UINT8 beaconIeLen, A_UINT8 assocReqLen,
|
||||
A_UINT8 assocRespLen,A_UINT8 *assocInfo);
|
||||
void ar6000_disconnect_event(struct ar6_softc *ar, A_UINT8 reason,
|
||||
A_UINT8 *bssid, A_UINT8 assocRespLen,
|
||||
A_UINT8 *assocInfo, A_UINT16 protocolReasonStatus);
|
||||
void ar6000_tkip_micerr_event(struct ar6_softc *ar, A_UINT8 keyid,
|
||||
A_BOOL ismcast);
|
||||
void ar6000_bitrate_rx(void *devt, A_INT32 rateKbps);
|
||||
void ar6000_channelList_rx(void *devt, A_INT8 numChan, A_UINT16 *chanList);
|
||||
void ar6000_regDomain_event(struct ar6_softc *ar, A_UINT32 regCode);
|
||||
void ar6000_txPwr_rx(void *devt, A_UINT8 txPwr);
|
||||
void ar6000_keepalive_rx(void *devt, A_UINT8 configured);
|
||||
void ar6000_neighborReport_event(struct ar6_softc *ar, int numAps,
|
||||
WMI_NEIGHBOR_INFO *info);
|
||||
void ar6000_set_numdataendpts(struct ar6_softc *ar, A_UINT32 num);
|
||||
void ar6000_scanComplete_event(struct ar6_softc *ar, A_STATUS status);
|
||||
void ar6000_targetStats_event(struct ar6_softc *ar, WMI_TARGET_STATS *pStats);
|
||||
void ar6000_rssiThreshold_event(struct ar6_softc *ar,
|
||||
WMI_RSSI_THRESHOLD_VAL newThreshold,
|
||||
A_INT16 rssi);
|
||||
void ar6000_reportError_event(struct ar6_softc *, WMI_TARGET_ERROR_VAL errorVal);
|
||||
void ar6000_cac_event(struct ar6_softc *ar, A_UINT8 ac, A_UINT8 cac_indication,
|
||||
A_UINT8 statusCode, A_UINT8 *tspecSuggestion);
|
||||
void ar6000_hbChallengeResp_event(struct ar6_softc *, A_UINT32 cookie, A_UINT32 source);
|
||||
void
|
||||
ar6000_roam_tbl_event(struct ar6_softc *ar, WMI_TARGET_ROAM_TBL *pTbl);
|
||||
|
||||
void
|
||||
ar6000_roam_data_event(struct ar6_softc *ar, WMI_TARGET_ROAM_DATA *p);
|
||||
|
||||
void
|
||||
ar6000_wow_list_event(struct ar6_softc *ar, A_UINT8 num_filters,
|
||||
WMI_GET_WOW_LIST_REPLY *wow_reply);
|
||||
|
||||
void ar6000_pmkid_list_event(void *devt, A_UINT8 numPMKID,
|
||||
WMI_PMKID *pmkidList);
|
||||
|
||||
void ar6000_gpio_intr_rx(A_UINT32 intr_mask, A_UINT32 input_values);
|
||||
void ar6000_gpio_data_rx(A_UINT32 reg_id, A_UINT32 value);
|
||||
void ar6000_gpio_ack_rx(void);
|
||||
|
||||
void ar6000_dbglog_init_done(struct ar6_softc *ar);
|
||||
|
||||
#ifdef SEND_EVENT_TO_APP
|
||||
void ar6000_send_event_to_app(struct ar6_softc *ar, A_UINT16 eventId, A_UINT8 *datap, int len);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
void ar6000_tcmd_rx_report_event(void *devt, A_UINT8 * results, int len);
|
||||
#endif
|
||||
|
||||
void ar6000_tx_retry_err_event(void *devt);
|
||||
|
||||
void ar6000_snrThresholdEvent_rx(void *devt,
|
||||
WMI_SNR_THRESHOLD_VAL newThreshold,
|
||||
A_UINT8 snr);
|
||||
|
||||
void ar6000_lqThresholdEvent_rx(void *devt, WMI_LQ_THRESHOLD_VAL range, A_UINT8 lqVal);
|
||||
|
||||
|
||||
void ar6000_ratemask_rx(void *devt, A_UINT16 ratemask);
|
||||
|
||||
A_STATUS ar6000_get_driver_cfg(struct net_device *dev,
|
||||
A_UINT16 cfgParam,
|
||||
void *result);
|
||||
void ar6000_bssInfo_event_rx(struct ar6_softc *ar, A_UINT8 *data, int len);
|
||||
|
||||
void ar6000_dbglog_event(struct ar6_softc *ar, A_UINT32 dropped,
|
||||
A_INT8 *buffer, A_UINT32 length);
|
||||
|
||||
int ar6000_dbglog_get_debug_logs(struct ar6_softc *ar);
|
||||
|
||||
void ar6000_indicate_tx_activity(void *devt, A_UINT8 trafficClass, A_BOOL Active);
|
||||
|
||||
void ar6000_dset_open_req(void *devt,
|
||||
A_UINT32 id,
|
||||
A_UINT32 targ_handle,
|
||||
A_UINT32 targ_reply_fn,
|
||||
A_UINT32 targ_reply_arg);
|
||||
void ar6000_dset_close(void *devt, A_UINT32 access_cookie);
|
||||
void ar6000_dset_data_req(void *devt,
|
||||
A_UINT32 access_cookie,
|
||||
A_UINT32 offset,
|
||||
A_UINT32 length,
|
||||
A_UINT32 targ_buf,
|
||||
A_UINT32 targ_reply_fn,
|
||||
A_UINT32 targ_reply_arg);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,993 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ATHDRV_LINUX_H
|
||||
#define _ATHDRV_LINUX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* There are two types of ioctl's here: Standard ioctls and
|
||||
* eXtended ioctls. All extended ioctls (XIOCTL) are multiplexed
|
||||
* off of the single ioctl command, AR6000_IOCTL_EXTENDED. The
|
||||
* arguments for every XIOCTL starts with a 32-bit command word
|
||||
* that is used to select which extended ioctl is in use. After
|
||||
* the command word are command-specific arguments.
|
||||
*/
|
||||
|
||||
/* Linux standard Wireless Extensions, private ioctl interfaces */
|
||||
#define IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0)
|
||||
#define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1)
|
||||
#define IEEE80211_IOCTL_SETKEY (SIOCIWFIRSTPRIV+2)
|
||||
#define IEEE80211_IOCTL_SETWMMPARAMS (SIOCIWFIRSTPRIV+3)
|
||||
#define IEEE80211_IOCTL_DELKEY (SIOCIWFIRSTPRIV+4)
|
||||
#define IEEE80211_IOCTL_GETWMMPARAMS (SIOCIWFIRSTPRIV+5)
|
||||
#define IEEE80211_IOCTL_SETOPTIE (SIOCIWFIRSTPRIV+6)
|
||||
#define IEEE80211_IOCTL_SETMLME (SIOCIWFIRSTPRIV+7)
|
||||
//#define IEEE80211_IOCTL_GETOPTIE (SIOCIWFIRSTPRIV+7)
|
||||
#define IEEE80211_IOCTL_ADDPMKID (SIOCIWFIRSTPRIV+8)
|
||||
//#define IEEE80211_IOCTL_SETAUTHALG (SIOCIWFIRSTPRIV+10)
|
||||
#define IEEE80211_IOCTL_LASTONE (SIOCIWFIRSTPRIV+9)
|
||||
|
||||
|
||||
|
||||
/* ====WMI Ioctls==== */
|
||||
/*
|
||||
*
|
||||
* Many ioctls simply provide WMI services to application code:
|
||||
* an application makes such an ioctl call with a set of arguments
|
||||
* that are packaged into the corresponding WMI message, and sent
|
||||
* to the Target.
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_GETREV (SIOCIWFIRSTPRIV+10)
|
||||
/*
|
||||
* arguments:
|
||||
* ar6000_version *revision
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SETPWR (SIOCIWFIRSTPRIV+11)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_POWER_MODE_CMD pwrModeCmd (see include/wmi.h)
|
||||
* uses: WMI_SET_POWER_MODE_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SETSCAN (SIOCIWFIRSTPRIV+12)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SCAN_PARAMS_CMD scanParams (see include/wmi.h)
|
||||
* uses: WMI_SET_SCAN_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SETLISTENINT (SIOCIWFIRSTPRIV+13)
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 listenInterval
|
||||
* uses: WMI_SET_LISTEN_INT_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SETBSSFILTER (SIOCIWFIRSTPRIV+14)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_BSS_FILTER filter (see include/wmi.h)
|
||||
* uses: WMI_SET_BSS_FILTER_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_CHANNELPARAMS (SIOCIWFIRSTPRIV+16)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_CHANNEL_PARAMS_CMD chParams
|
||||
* uses: WMI_SET_CHANNEL_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_PROBEDSSID (SIOCIWFIRSTPRIV+17)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_PROBED_SSID_CMD probedSsids (see include/wmi.h)
|
||||
* uses: WMI_SETPROBED_SSID_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_PMPARAMS (SIOCIWFIRSTPRIV+18)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_POWER_PARAMS_CMD powerParams (see include/wmi.h)
|
||||
* uses: WMI_SET_POWER_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_BADAP (SIOCIWFIRSTPRIV+19)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_ADD_BAD_AP_CMD badAPs (see include/wmi.h)
|
||||
* uses: WMI_ADD_BAD_AP_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_GET_QOS_QUEUE (SIOCIWFIRSTPRIV+20)
|
||||
/*
|
||||
* arguments:
|
||||
* ar6000_queuereq queueRequest (see below)
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_CREATE_QOS (SIOCIWFIRSTPRIV+21)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_CREATE_PSTREAM createPstreamCmd (see include/wmi.h)
|
||||
* uses: WMI_CREATE_PSTREAM_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_DELETE_QOS (SIOCIWFIRSTPRIV+22)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_DELETE_PSTREAM_CMD deletePstreamCmd (see include/wmi.h)
|
||||
* uses: WMI_DELETE_PSTREAM_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_SNRTHRESHOLD (SIOCIWFIRSTPRIV+23)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SNR_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
|
||||
* uses: WMI_SNR_THRESHOLD_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_ERROR_REPORT_BITMASK (SIOCIWFIRSTPRIV+24)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_TARGET_ERROR_REPORT_BITMASK errorReportBitMask (see include/wmi.h)
|
||||
* uses: WMI_TARGET_ERROR_REPORT_BITMASK_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_GET_TARGET_STATS (SIOCIWFIRSTPRIV+25)
|
||||
/*
|
||||
* arguments:
|
||||
* TARGET_STATS *targetStats (see below)
|
||||
* uses: WMI_GET_STATISTICS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_ASSOC_INFO (SIOCIWFIRSTPRIV+26)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SET_ASSOC_INFO_CMD setAssocInfoCmd
|
||||
* uses: WMI_SET_ASSOC_INFO_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_ACCESS_PARAMS (SIOCIWFIRSTPRIV+27)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SET_ACCESS_PARAMS_CMD setAccessParams (see include/wmi.h)
|
||||
* uses: WMI_SET_ACCESS_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_BMISS_TIME (SIOCIWFIRSTPRIV+28)
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 beaconMissTime
|
||||
* uses: WMI_SET_BMISS_TIME_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_DISC_TIMEOUT (SIOCIWFIRSTPRIV+29)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_DISC_TIMEOUT_CMD disconnectTimeoutCmd (see include/wmi.h)
|
||||
* uses: WMI_SET_DISC_TIMEOUT_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_IOCTL_WMI_SET_IBSS_PM_CAPS (SIOCIWFIRSTPRIV+30)
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_IBSS_PM_CAPS_CMD ibssPowerMgmtCapsCmd
|
||||
* uses: WMI_SET_IBSS_PM_CAPS_CMDID
|
||||
*/
|
||||
|
||||
/*
|
||||
* There is a very small space available for driver-private
|
||||
* wireless ioctls. In order to circumvent this limitation,
|
||||
* we multiplex a bunch of ioctls (XIOCTLs) on top of a
|
||||
* single AR6000_IOCTL_EXTENDED ioctl.
|
||||
*/
|
||||
#define AR6000_IOCTL_EXTENDED (SIOCIWFIRSTPRIV+31)
|
||||
|
||||
|
||||
/* ====BMI Extended Ioctls==== */
|
||||
|
||||
#define AR6000_XIOCTL_BMI_DONE 1
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_DONE)
|
||||
* uses: BMI_DONE
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_READ_MEMORY 2
|
||||
/*
|
||||
* arguments:
|
||||
* union {
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_READ_MEMORY)
|
||||
* UINT32 address
|
||||
* UINT32 length
|
||||
* }
|
||||
* char results[length]
|
||||
* }
|
||||
* uses: BMI_READ_MEMORY
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_WRITE_MEMORY 3
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_MEMORY)
|
||||
* UINT32 address
|
||||
* UINT32 length
|
||||
* char data[length]
|
||||
* uses: BMI_WRITE_MEMORY
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_EXECUTE 4
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_EXECUTE)
|
||||
* UINT32 TargetAddress
|
||||
* UINT32 parameter
|
||||
* uses: BMI_EXECUTE
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_SET_APP_START 5
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_SET_APP_START)
|
||||
* UINT32 TargetAddress
|
||||
* uses: BMI_SET_APP_START
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_READ_SOC_REGISTER 6
|
||||
/*
|
||||
* arguments:
|
||||
* union {
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_READ_SOC_REGISTER)
|
||||
* UINT32 TargetAddress, 32-bit aligned
|
||||
* }
|
||||
* UINT32 result
|
||||
* }
|
||||
* uses: BMI_READ_SOC_REGISTER
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER 7
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER)
|
||||
* UINT32 TargetAddress, 32-bit aligned
|
||||
* UINT32 newValue
|
||||
* }
|
||||
* uses: BMI_WRITE_SOC_REGISTER
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_TEST 8
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_TEST)
|
||||
* UINT32 address
|
||||
* UINT32 length
|
||||
* UINT32 count
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Historical Host-side DataSet support */
|
||||
#define AR6000_XIOCTL_UNUSED9 9
|
||||
#define AR6000_XIOCTL_UNUSED10 10
|
||||
#define AR6000_XIOCTL_UNUSED11 11
|
||||
|
||||
/* ====Misc Extended Ioctls==== */
|
||||
|
||||
#define AR6000_XIOCTL_FORCE_TARGET_RESET 12
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_FORCE_TARGET_RESET)
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HTC_RAW_INTERFACE
|
||||
/* HTC Raw Interface Ioctls */
|
||||
#define AR6000_XIOCTL_HTC_RAW_OPEN 13
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_OPEN)
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_HTC_RAW_CLOSE 14
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_CLOSE)
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_HTC_RAW_READ 15
|
||||
/*
|
||||
* arguments:
|
||||
* union {
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_READ)
|
||||
* UINT32 mailboxID
|
||||
* UINT32 length
|
||||
* }
|
||||
* results[length]
|
||||
* }
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_HTC_RAW_WRITE 16
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_WRITE)
|
||||
* UINT32 mailboxID
|
||||
* UINT32 length
|
||||
* char buffer[length]
|
||||
*/
|
||||
#endif /* HTC_RAW_INTERFACE */
|
||||
|
||||
#define AR6000_XIOCTL_CHECK_TARGET_READY 17
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_CHECK_TARGET_READY)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ====GPIO (General Purpose I/O) Extended Ioctls==== */
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_OUTPUT_SET 18
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_OUTPUT_SET)
|
||||
* ar6000_gpio_output_set_cmd_s (see below)
|
||||
* uses: WMIX_GPIO_OUTPUT_SET_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_INPUT_GET 19
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_INPUT_GET)
|
||||
* uses: WMIX_GPIO_INPUT_GET_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_REGISTER_SET 20
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_SET)
|
||||
* ar6000_gpio_register_cmd_s (see below)
|
||||
* uses: WMIX_GPIO_REGISTER_SET_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_REGISTER_GET 21
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_GET)
|
||||
* ar6000_gpio_register_cmd_s (see below)
|
||||
* uses: WMIX_GPIO_REGISTER_GET_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_INTR_ACK 22
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_ACK)
|
||||
* ar6000_cpio_intr_ack_cmd_s (see below)
|
||||
* uses: WMIX_GPIO_INTR_ACK_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_GPIO_INTR_WAIT 23
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_WAIT)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ====more wireless commands==== */
|
||||
|
||||
#define AR6000_XIOCTL_SET_ADHOC_BSSID 24
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_SET_ADHOC_BSSID)
|
||||
* WMI_SET_ADHOC_BSSID_CMD setAdHocBssidCmd (see include/wmi.h)
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_SET_OPT_MODE 25
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_SET_OPT_MODE)
|
||||
* WMI_SET_OPT_MODE_CMD setOptModeCmd (see include/wmi.h)
|
||||
* uses: WMI_SET_OPT_MODE_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_OPT_SEND_FRAME 26
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_OPT_SEND_FRAME)
|
||||
* WMI_OPT_TX_FRAME_CMD optTxFrameCmd (see include/wmi.h)
|
||||
* uses: WMI_OPT_TX_FRAME_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_SET_ADHOC_BEACON_INTVAL 27
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_SET_ADHOC_BEACON_INTVAL)
|
||||
* WMI_BEACON_INT_CMD beaconIntCmd (see include/wmi.h)
|
||||
* uses: WMI_SET_BEACON_INT_CMDID
|
||||
*/
|
||||
|
||||
|
||||
#define IEEE80211_IOCTL_SETAUTHALG 28
|
||||
|
||||
|
||||
#define AR6000_XIOCTL_SET_VOICE_PKT_SIZE 29
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_SET_VOICE_PKT_SIZE)
|
||||
* WMI_SET_VOICE_PKT_SIZE_CMD setVoicePktSizeCmd (see include/wmi.h)
|
||||
* uses: WMI_SET_VOICE_PKT_SIZE_CMDID
|
||||
*/
|
||||
|
||||
|
||||
#define AR6000_XIOCTL_SET_MAX_SP 30
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_SET_MAX_SP)
|
||||
* WMI_SET_MAX_SP_LEN_CMD maxSPLen(see include/wmi.h)
|
||||
* uses: WMI_SET_MAX_SP_LEN_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_GET_ROAM_TBL 31
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_ROAM_CTRL 32
|
||||
|
||||
#define AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS 33
|
||||
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS)
|
||||
* WMI_SET_POWERSAVE_TIMERS_CMD powerSaveTimers(see include/wmi.h)
|
||||
* WMI_SET_POWERSAVE_TIMERS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTRL_WMI_GET_POWER_MODE 34
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTRL_WMI_GET_POWER_MODE)
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTRL_WMI_SET_WLAN_STATE 35
|
||||
typedef enum {
|
||||
WLAN_DISABLED,
|
||||
WLAN_ENABLED
|
||||
} AR6000_WLAN_STATE;
|
||||
/*
|
||||
* arguments:
|
||||
* enable/disable
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_GET_ROAM_DATA 36
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SETRETRYLIMITS 37
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SET_RETRY_LIMITS_CMD ibssSetRetryLimitsCmd
|
||||
* uses: WMI_SET_RETRY_LIMITS_CMDID
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
/* ====extended commands for radio test ==== */
|
||||
|
||||
#define AR6000_XIOCTL_TCMD_CONT_TX 38
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_TX)
|
||||
* WMI_TCMD_CONT_TX_CMD contTxCmd (see include/wmi.h)
|
||||
* uses: WMI_TCMD_CONT_TX_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_TCMD_CONT_RX 39
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_RX)
|
||||
* WMI_TCMD_CONT_RX_CMD rxCmd (see include/wmi.h)
|
||||
* uses: WMI_TCMD_CONT_RX_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_TCMD_PM 40
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_TCMD_PM)
|
||||
* WMI_TCMD_PM_CMD pmCmd (see include/wmi.h)
|
||||
* uses: WMI_TCMD_PM_CMDID
|
||||
*/
|
||||
|
||||
#endif /* CONFIG_HOST_TCMD_SUPPORT */
|
||||
|
||||
#define AR6000_XIOCTL_WMI_STARTSCAN 41
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_STARTSCAN)
|
||||
* UINT8 scanType
|
||||
* UINT8 scanConnected
|
||||
* A_BOOL forceFgScan
|
||||
* uses: WMI_START_SCAN_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SETFIXRATES 42
|
||||
|
||||
#define AR6000_XIOCTL_WMI_GETFIXRATES 43
|
||||
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_RSSITHRESHOLD 44
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_RSSI_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
|
||||
* uses: WMI_RSSI_THRESHOLD_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_CLR_RSSISNR 45
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_CLR_RSSISNR_CMD thresholdParams (see include/wmi.h)
|
||||
* uses: WMI_CLR_RSSISNR_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_LQTHRESHOLD 46
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_LQ_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
|
||||
* uses: WMI_LQ_THRESHOLD_PARAMS_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_RTS 47
|
||||
/*
|
||||
* arguments:
|
||||
* WMI_SET_RTS_MODE_CMD (see include/wmi.h)
|
||||
* uses: WMI_SET_RTS_MODE_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_LPREAMBLE 48
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_AUTHMODE 49
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_AUTHMODE)
|
||||
* UINT8 mode
|
||||
* uses: WMI_SET_RECONNECT_AUTH_MODE_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_REASSOCMODE 50
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_WMM)
|
||||
* UINT8 mode
|
||||
* uses: WMI_SET_WMM_CMDID
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_WMM 51
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS)
|
||||
* UINT32 frequency
|
||||
* UINT8 threshold
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS 52
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP)
|
||||
* UINT32 cookie
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP 53
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_GET_RD)
|
||||
* UINT32 regDomain
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_GET_RD 54
|
||||
|
||||
#define AR6000_XIOCTL_DIAG_READ 55
|
||||
|
||||
#define AR6000_XIOCTL_DIAG_WRITE 56
|
||||
|
||||
/*
|
||||
* arguments cmd (AR6000_XIOCTL_SET_TXOP)
|
||||
* WMI_TXOP_CFG txopEnable
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_TXOP 57
|
||||
|
||||
#ifdef USER_KEYS
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_USER_SETKEYS)
|
||||
* UINT32 keyOpCtrl
|
||||
* uses AR6000_USER_SETKEYS_INFO
|
||||
*/
|
||||
#define AR6000_XIOCTL_USER_SETKEYS 58
|
||||
#endif /* USER_KEYS */
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_KEEPALIVE 59
|
||||
/*
|
||||
* arguments:
|
||||
* UINT8 cmd (AR6000_XIOCTL_WMI_SET_KEEPALIVE)
|
||||
* UINT8 keepaliveInterval
|
||||
* uses: WMI_SET_KEEPALIVE_CMDID
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_GET_KEEPALIVE 60
|
||||
/*
|
||||
* arguments:
|
||||
* UINT8 cmd (AR6000_XIOCTL_WMI_GET_KEEPALIVE)
|
||||
* UINT8 keepaliveInterval
|
||||
* A_BOOL configured
|
||||
* uses: WMI_GET_KEEPALIVE_CMDID
|
||||
*/
|
||||
|
||||
/* ====ROM Patching Extended Ioctls==== */
|
||||
|
||||
#define AR6000_XIOCTL_BMI_ROMPATCH_INSTALL 61
|
||||
/*
|
||||
* arguments:
|
||||
* union {
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_INSTALL)
|
||||
* UINT32 ROM Address
|
||||
* UINT32 RAM Address
|
||||
* UINT32 number of bytes
|
||||
* UINT32 activate? (0 or 1)
|
||||
* }
|
||||
* A_UINT32 resulting rompatch ID
|
||||
* }
|
||||
* uses: BMI_ROMPATCH_INSTALL
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL 62
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL)
|
||||
* UINT32 rompatch ID
|
||||
* }
|
||||
* uses: BMI_ROMPATCH_UNINSTALL
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE 63
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE)
|
||||
* UINT32 rompatch count
|
||||
* UINT32 rompatch IDs[rompatch count]
|
||||
* }
|
||||
* uses: BMI_ROMPATCH_ACTIVATE
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE 64
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE)
|
||||
* UINT32 rompatch count
|
||||
* UINT32 rompatch IDs[rompatch count]
|
||||
* }
|
||||
* uses: BMI_ROMPATCH_DEACTIVATE
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_APPIE 65
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_APPIE)
|
||||
* UINT32 app_frmtype;
|
||||
* UINT32 app_buflen;
|
||||
* UINT8 app_buf[];
|
||||
* }
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_MGMT_FRM_RX_FILTER 66
|
||||
/*
|
||||
* arguments:
|
||||
* A_UINT32 filter_type;
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_DBGLOG_CFG_MODULE 67
|
||||
|
||||
#define AR6000_XIOCTL_DBGLOG_GET_DEBUG_LOGS 68
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_WSC_STATUS 70
|
||||
/*
|
||||
* arguments:
|
||||
* A_UINT32 wsc_status;
|
||||
* (WSC_REG_INACTIVE or WSC_REG_ACTIVE)
|
||||
*/
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* A_UINT8 streamType;
|
||||
* A_UINT8 status;
|
||||
* }
|
||||
* uses: WMI_SET_BT_STATUS_CMDID
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_BT_STATUS 71
|
||||
|
||||
/*
|
||||
* arguments:
|
||||
* struct {
|
||||
* A_UINT8 paramType;
|
||||
* union {
|
||||
* A_UINT8 noSCOPkts;
|
||||
* BT_PARAMS_A2DP a2dpParams;
|
||||
* BT_COEX_REGS regs;
|
||||
* };
|
||||
* }
|
||||
* uses: WMI_SET_BT_PARAM_CMDID
|
||||
*/
|
||||
#define AR6000_XIOCTL_WMI_SET_BT_PARAMS 72
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_HOST_SLEEP_MODE 73
|
||||
#define AR6000_XIOCTL_WMI_SET_WOW_MODE 74
|
||||
#define AR6000_XIOCTL_WMI_GET_WOW_LIST 75
|
||||
#define AR6000_XIOCTL_WMI_ADD_WOW_PATTERN 76
|
||||
#define AR6000_XIOCTL_WMI_DEL_WOW_PATTERN 77
|
||||
|
||||
|
||||
|
||||
#define AR6000_XIOCTL_TARGET_INFO 78
|
||||
/*
|
||||
* arguments:
|
||||
* UINT32 cmd (AR6000_XIOCTL_TARGET_INFO)
|
||||
* A_UINT32 TargetVersion (returned)
|
||||
* A_UINT32 TargetType (returned)
|
||||
* (See also bmi_msg.h target_ver and target_type)
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_DUMP_HTC_CREDIT_STATE 79
|
||||
/*
|
||||
* arguments:
|
||||
* none
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE 80
|
||||
/*
|
||||
* This ioctl is used to emulate traffic activity
|
||||
* timeouts. Activity/inactivity will trigger the driver
|
||||
* to re-balance credits.
|
||||
*
|
||||
* arguments:
|
||||
* ar6000_traffic_activity_change
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_CONNECT_CTRL_FLAGS 81
|
||||
/*
|
||||
* This ioctl is used to set the connect control flags
|
||||
*
|
||||
* arguments:
|
||||
* A_UINT32 connectCtrlFlags
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_AKMP_PARAMS 82
|
||||
/*
|
||||
* This IOCTL sets any Authentication,Key Management and Protection
|
||||
* related parameters. This is used along with the information set in
|
||||
* Connect Command.
|
||||
* Currently this enables Multiple PMKIDs to an AP.
|
||||
*
|
||||
* arguments:
|
||||
* struct {
|
||||
* A_UINT32 akmpInfo;
|
||||
* }
|
||||
* uses: WMI_SET_AKMP_PARAMS_CMD
|
||||
*/
|
||||
|
||||
#define AR6000_XIOCTL_WMI_GET_PMKID_LIST 83
|
||||
|
||||
#define AR6000_XIOCTL_WMI_SET_PMKID_LIST 84
|
||||
/*
|
||||
* This IOCTL is used to set a list of PMKIDs. This list of
|
||||
* PMKIDs is used in the [Re]AssocReq Frame. This list is used
|
||||
* only if the MultiPMKID option is enabled via the
|
||||
* AR6000_XIOCTL_WMI_SET_AKMP_PARAMS IOCTL.
|
||||
*
|
||||
* arguments:
|
||||
* struct {
|
||||
* A_UINT32 numPMKID;
|
||||
* WMI_PMKID pmkidList[WMI_MAX_PMKID_CACHE];
|
||||
* }
|
||||
* uses: WMI_SET_PMKIDLIST_CMD
|
||||
*/
|
||||
|
||||
/* Historical DSETPATCH support for INI patches */
|
||||
#define AR6000_XIOCTL_UNUSED90 90
|
||||
|
||||
|
||||
|
||||
/* used by AR6000_IOCTL_WMI_GETREV */
|
||||
struct ar6000_version {
|
||||
A_UINT32 host_ver;
|
||||
A_UINT32 target_ver;
|
||||
};
|
||||
|
||||
/* used by AR6000_IOCTL_WMI_GET_QOS_QUEUE */
|
||||
struct ar6000_queuereq {
|
||||
A_UINT8 trafficClass;
|
||||
A_UINT16 activeTsids;
|
||||
};
|
||||
|
||||
/* used by AR6000_IOCTL_WMI_GET_TARGET_STATS */
|
||||
typedef struct targetStats_t {
|
||||
A_UINT64 tx_packets;
|
||||
A_UINT64 tx_bytes;
|
||||
A_UINT64 tx_unicast_pkts;
|
||||
A_UINT64 tx_unicast_bytes;
|
||||
A_UINT64 tx_multicast_pkts;
|
||||
A_UINT64 tx_multicast_bytes;
|
||||
A_UINT64 tx_broadcast_pkts;
|
||||
A_UINT64 tx_broadcast_bytes;
|
||||
A_UINT64 tx_rts_success_cnt;
|
||||
A_UINT64 tx_packet_per_ac[4];
|
||||
|
||||
A_UINT64 tx_errors;
|
||||
A_UINT64 tx_failed_cnt;
|
||||
A_UINT64 tx_retry_cnt;
|
||||
A_UINT64 tx_rts_fail_cnt;
|
||||
A_INT32 tx_unicast_rate;
|
||||
A_UINT64 rx_packets;
|
||||
A_UINT64 rx_bytes;
|
||||
A_UINT64 rx_unicast_pkts;
|
||||
A_UINT64 rx_unicast_bytes;
|
||||
A_UINT64 rx_multicast_pkts;
|
||||
A_UINT64 rx_multicast_bytes;
|
||||
A_UINT64 rx_broadcast_pkts;
|
||||
A_UINT64 rx_broadcast_bytes;
|
||||
A_UINT64 rx_fragment_pkt;
|
||||
|
||||
A_UINT64 rx_errors;
|
||||
A_UINT64 rx_crcerr;
|
||||
A_UINT64 rx_key_cache_miss;
|
||||
A_UINT64 rx_decrypt_err;
|
||||
A_UINT64 rx_duplicate_frames;
|
||||
A_INT32 rx_unicast_rate;
|
||||
|
||||
A_UINT64 tkip_local_mic_failure;
|
||||
A_UINT64 tkip_counter_measures_invoked;
|
||||
A_UINT64 tkip_replays;
|
||||
A_UINT64 tkip_format_errors;
|
||||
A_UINT64 ccmp_format_errors;
|
||||
A_UINT64 ccmp_replays;
|
||||
|
||||
A_UINT64 power_save_failure_cnt;
|
||||
A_INT16 noise_floor_calibation;
|
||||
|
||||
A_UINT64 cs_bmiss_cnt;
|
||||
A_UINT64 cs_lowRssi_cnt;
|
||||
A_UINT64 cs_connect_cnt;
|
||||
A_UINT64 cs_disconnect_cnt;
|
||||
A_UINT8 cs_aveBeacon_snr;
|
||||
A_INT16 cs_aveBeacon_rssi;
|
||||
A_UINT8 cs_lastRoam_msec;
|
||||
A_UINT8 cs_snr;
|
||||
A_INT16 cs_rssi;
|
||||
|
||||
A_UINT32 lq_val;
|
||||
|
||||
A_UINT32 wow_num_pkts_dropped;
|
||||
A_UINT8 wow_num_host_pkt_wakeups;
|
||||
A_UINT8 wow_num_host_event_wakeups;
|
||||
A_UINT16 wow_num_events_discarded;
|
||||
|
||||
}TARGET_STATS;
|
||||
|
||||
typedef struct targetStats_cmd_t {
|
||||
TARGET_STATS targetStats;
|
||||
int clearStats;
|
||||
} TARGET_STATS_CMD;
|
||||
|
||||
/* used by AR6000_XIOCTL_USER_SETKEYS */
|
||||
|
||||
/*
|
||||
* Setting this bit to 1 doesnot initialize the RSC on the firmware
|
||||
*/
|
||||
#define AR6000_XIOCTL_USER_SETKEYS_RSC_CTRL 1
|
||||
#define AR6000_USER_SETKEYS_RSC_UNCHANGED 0x00000002
|
||||
|
||||
typedef struct {
|
||||
A_UINT32 keyOpCtrl; /* Bit Map of Key Mgmt Ctrl Flags */
|
||||
} AR6000_USER_SETKEYS_INFO;
|
||||
|
||||
|
||||
/* used by AR6000_XIOCTL_GPIO_OUTPUT_SET */
|
||||
struct ar6000_gpio_output_set_cmd_s {
|
||||
A_UINT32 set_mask;
|
||||
A_UINT32 clear_mask;
|
||||
A_UINT32 enable_mask;
|
||||
A_UINT32 disable_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* used by AR6000_XIOCTL_GPIO_REGISTER_GET and AR6000_XIOCTL_GPIO_REGISTER_SET
|
||||
*/
|
||||
struct ar6000_gpio_register_cmd_s {
|
||||
A_UINT32 gpioreg_id;
|
||||
A_UINT32 value;
|
||||
};
|
||||
|
||||
/* used by AR6000_XIOCTL_GPIO_INTR_ACK */
|
||||
struct ar6000_gpio_intr_ack_cmd_s {
|
||||
A_UINT32 ack_mask;
|
||||
};
|
||||
|
||||
/* used by AR6000_XIOCTL_GPIO_INTR_WAIT */
|
||||
struct ar6000_gpio_intr_wait_cmd_s {
|
||||
A_UINT32 intr_mask;
|
||||
A_UINT32 input_values;
|
||||
};
|
||||
|
||||
/* used by the AR6000_XIOCTL_DBGLOG_CFG_MODULE */
|
||||
typedef struct ar6000_dbglog_module_config_s {
|
||||
A_UINT32 valid;
|
||||
A_UINT16 mmask;
|
||||
A_UINT16 tsr;
|
||||
A_BOOL rep;
|
||||
A_UINT16 size;
|
||||
} DBGLOG_MODULE_CONFIG;
|
||||
|
||||
typedef struct user_rssi_thold_t {
|
||||
A_INT16 tag;
|
||||
A_INT16 rssi;
|
||||
} USER_RSSI_THOLD;
|
||||
|
||||
typedef struct user_rssi_params_t {
|
||||
A_UINT8 weight;
|
||||
A_UINT32 pollTime;
|
||||
USER_RSSI_THOLD tholds[12];
|
||||
} USER_RSSI_PARAMS;
|
||||
|
||||
/*
|
||||
* Host driver may have some config parameters. Typically, these
|
||||
* config params are one time config parameters. These could
|
||||
* correspond to any of the underlying modules. Host driver exposes
|
||||
* an api for the underlying modules to get this config.
|
||||
*/
|
||||
#define AR6000_DRIVER_CFG_BASE 0x8000
|
||||
|
||||
/* Should driver perform wlan node caching? */
|
||||
#define AR6000_DRIVER_CFG_GET_WLANNODECACHING 0x8001
|
||||
/*Should we log raw WMI msgs */
|
||||
#define AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS 0x8002
|
||||
|
||||
/* used by AR6000_XIOCTL_DIAG_READ & AR6000_XIOCTL_DIAG_WRITE */
|
||||
struct ar6000_diag_window_cmd_s {
|
||||
unsigned int addr;
|
||||
unsigned int value;
|
||||
};
|
||||
|
||||
|
||||
struct ar6000_traffic_activity_change {
|
||||
A_UINT32 StreamID; /* stream ID to indicate activity change */
|
||||
A_UINT32 Active; /* active (1) or inactive (0) */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/athtypes_linux.h#1 $
|
||||
*
|
||||
* This file contains the definitions of the basic atheros data types.
|
||||
* It is used to map the data types in atheros files to a platform specific
|
||||
* type.
|
||||
*
|
||||
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ATHTYPES_LINUX_H_
|
||||
#define _ATHTYPES_LINUX_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
|
||||
typedef int8_t A_INT8;
|
||||
typedef int16_t A_INT16;
|
||||
typedef int32_t A_INT32;
|
||||
typedef int64_t A_INT64;
|
||||
|
||||
typedef u_int8_t A_UINT8;
|
||||
typedef u_int16_t A_UINT16;
|
||||
typedef u_int32_t A_UINT32;
|
||||
typedef u_int64_t A_UINT64;
|
||||
|
||||
typedef int A_BOOL;
|
||||
typedef char A_CHAR;
|
||||
typedef unsigned char A_UCHAR;
|
||||
typedef unsigned long A_ATH_TIMER;
|
||||
|
||||
|
||||
#endif /* _ATHTYPES_LINUX_H_ */
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_LINUX_H_
|
||||
#define _CONFIG_LINUX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Host-side GPIO support is optional.
|
||||
* If run-time access to GPIO pins is not required, then
|
||||
* this should be changed to #undef.
|
||||
*/
|
||||
#define CONFIG_HOST_GPIO_SUPPORT
|
||||
|
||||
/*
|
||||
* Host side Test Command support
|
||||
*/
|
||||
#define CONFIG_HOST_TCMD_SUPPORT
|
||||
|
||||
#define USE_4BYTE_REGISTER_ACCESS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_LINUX_H_
|
||||
#define _DEBUG_LINUX_H_
|
||||
|
||||
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
|
||||
|
||||
extern A_UINT32 g_dbg_flags;
|
||||
|
||||
#define DBGFMT "%s() : "
|
||||
#define DBGARG __func__
|
||||
#define DBGFN A_PRINTF
|
||||
|
||||
/* ------- Debug related stuff ------- */
|
||||
enum {
|
||||
ATH_DEBUG_SEND = 0x0001,
|
||||
ATH_DEBUG_RECV = 0x0002,
|
||||
ATH_DEBUG_SYNC = 0x0004,
|
||||
ATH_DEBUG_DUMP = 0x0008,
|
||||
ATH_DEBUG_IRQ = 0x0010,
|
||||
ATH_DEBUG_TRC = 0x0020,
|
||||
ATH_DEBUG_WARN = 0x0040,
|
||||
ATH_DEBUG_ERR = 0x0080,
|
||||
ATH_LOG_INF = 0x0100,
|
||||
ATH_DEBUG_BMI = 0x0110,
|
||||
ATH_DEBUG_WMI = 0x0120,
|
||||
ATH_DEBUG_HIF = 0x0140,
|
||||
ATH_DEBUG_HTC = 0x0180,
|
||||
ATH_DEBUG_WLAN = 0x1000,
|
||||
ATH_LOG_ERR = 0x1010,
|
||||
ATH_DEBUG_ANY = 0xFFFF,
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define A_DPRINTF(f, a) \
|
||||
if(g_dbg_flags & (f)) \
|
||||
{ \
|
||||
DBGFN a ; \
|
||||
}
|
||||
|
||||
|
||||
// TODO FIX usage of A_PRINTF!
|
||||
#define AR_DEBUG_LVL_CHECK(lvl) (debughtc & (lvl))
|
||||
#define AR_DEBUG_PRINTBUF(buffer, length, desc) do { \
|
||||
if (debughtc & ATH_DEBUG_DUMP) { \
|
||||
DebugDumpBytes(buffer, length,desc); \
|
||||
} \
|
||||
} while(0)
|
||||
#define PRINTX_ARG(arg...) arg
|
||||
#define AR_DEBUG_PRINTF(flags, args) do { \
|
||||
if (debughtc & (flags)) { \
|
||||
A_PRINTF(KERN_ALERT PRINTX_ARG args); \
|
||||
} \
|
||||
} while (0)
|
||||
#define AR_DEBUG_ASSERT(test) do { \
|
||||
if (!(test)) { \
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,#test)); \
|
||||
} \
|
||||
} while(0)
|
||||
extern int debughtc;
|
||||
#else
|
||||
#define AR_DEBUG_PRINTF(flags, args)
|
||||
#define AR_DEBUG_PRINTBUF(buffer, length, desc)
|
||||
#define AR_DEBUG_ASSERT(test)
|
||||
#define AR_DEBUG_LVL_CHECK(lvl) 0
|
||||
#define A_DPRINTF(f, a)
|
||||
#endif
|
||||
|
||||
#endif /* _DEBUG_LINUX_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,225 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <a_config.h>
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "htc_packet.h"
|
||||
|
||||
#define AR6000_DATA_OFFSET 64
|
||||
|
||||
void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt)
|
||||
{
|
||||
skb_queue_tail((struct sk_buff_head *) q, (struct sk_buff *) pkt);
|
||||
}
|
||||
|
||||
void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt)
|
||||
{
|
||||
skb_queue_head((struct sk_buff_head *) q, (struct sk_buff *) pkt);
|
||||
}
|
||||
|
||||
void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q)
|
||||
{
|
||||
return((void *) skb_dequeue((struct sk_buff_head *) q));
|
||||
}
|
||||
|
||||
int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q)
|
||||
{
|
||||
return(skb_queue_len((struct sk_buff_head *) q));
|
||||
}
|
||||
|
||||
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q)
|
||||
{
|
||||
return(skb_queue_empty((struct sk_buff_head *) q));
|
||||
}
|
||||
|
||||
void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q)
|
||||
{
|
||||
skb_queue_head_init((struct sk_buff_head *) q);
|
||||
}
|
||||
|
||||
void *
|
||||
a_netbuf_alloc(int size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
skb = dev_alloc_skb(AR6000_DATA_OFFSET + sizeof(HTC_PACKET) + size);
|
||||
skb_reserve(skb, AR6000_DATA_OFFSET + sizeof(HTC_PACKET));
|
||||
return ((void *)skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an SKB w.o. any encapsulation requirement.
|
||||
*/
|
||||
void *
|
||||
a_netbuf_alloc_raw(int size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = dev_alloc_skb(size);
|
||||
|
||||
return ((void *)skb);
|
||||
}
|
||||
|
||||
void
|
||||
a_netbuf_free(void *bufPtr)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)bufPtr;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
A_UINT32
|
||||
a_netbuf_to_len(void *bufPtr)
|
||||
{
|
||||
return (((struct sk_buff *)bufPtr)->len);
|
||||
}
|
||||
|
||||
void *
|
||||
a_netbuf_to_data(void *bufPtr)
|
||||
{
|
||||
return (((struct sk_buff *)bufPtr)->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add len # of bytes to the beginning of the network buffer
|
||||
* pointed to by bufPtr
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_push(void *bufPtr, A_INT32 len)
|
||||
{
|
||||
skb_push((struct sk_buff *)bufPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add len # of bytes to the beginning of the network buffer
|
||||
* pointed to by bufPtr and also fill with data
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len)
|
||||
{
|
||||
skb_push((struct sk_buff *) bufPtr, len);
|
||||
A_MEMCPY(((struct sk_buff *)bufPtr)->data, srcPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add len # of bytes to the end of the network buffer
|
||||
* pointed to by bufPtr
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_put(void *bufPtr, A_INT32 len)
|
||||
{
|
||||
skb_put((struct sk_buff *)bufPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add len # of bytes to the end of the network buffer
|
||||
* pointed to by bufPtr and also fill with data
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len)
|
||||
{
|
||||
char *start = ((struct sk_buff *)bufPtr)->data +
|
||||
((struct sk_buff *)bufPtr)->len;
|
||||
skb_put((struct sk_buff *)bufPtr, len);
|
||||
A_MEMCPY(start, srcPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Trim the network buffer pointed to by bufPtr to len # of bytes
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_setlen(void *bufPtr, A_INT32 len)
|
||||
{
|
||||
skb_trim((struct sk_buff *)bufPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chop of len # of bytes from the end of the buffer.
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_trim(void *bufPtr, A_INT32 len)
|
||||
{
|
||||
skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chop of len # of bytes from the end of the buffer and return the data.
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len)
|
||||
{
|
||||
char *start = ((struct sk_buff *)bufPtr)->data +
|
||||
(((struct sk_buff *)bufPtr)->len - len);
|
||||
|
||||
A_MEMCPY(dstPtr, start, len);
|
||||
skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the number of bytes available to a a_netbuf_push()
|
||||
*/
|
||||
A_INT32
|
||||
a_netbuf_headroom(void *bufPtr)
|
||||
{
|
||||
return (skb_headroom((struct sk_buff *)bufPtr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes specified number of bytes from the beginning of the buffer
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_pull(void *bufPtr, A_INT32 len)
|
||||
{
|
||||
skb_pull((struct sk_buff *)bufPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes specified number of bytes from the beginning of the buffer
|
||||
* and return the data
|
||||
*/
|
||||
A_STATUS
|
||||
a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len)
|
||||
{
|
||||
A_MEMCPY(dstPtr, ((struct sk_buff *)bufPtr)->data, len);
|
||||
skb_pull((struct sk_buff *)bufPtr, len);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/osapi_linux.h#1 $
|
||||
*
|
||||
* This file contains the definitions of the basic atheros data types.
|
||||
* It is used to map the data types in atheros files to a platform specific
|
||||
* type.
|
||||
*
|
||||
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OSAPI_LINUX_H_
|
||||
#define _OSAPI_LINUX_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
#include <linux/jiffies.h>
|
||||
#endif
|
||||
#include <linux/timer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/wait.h>
|
||||
#ifdef KERNEL_2_4
|
||||
#include <asm/arch/irq.h>
|
||||
#include <asm/irq.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __ATTRIB_PACK __attribute__ ((packed))
|
||||
#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
|
||||
#define __ATTRIB_NORETURN __attribute__ ((noreturn))
|
||||
#ifndef INLINE
|
||||
#define INLINE __inline__
|
||||
#endif
|
||||
#else /* Not GCC */
|
||||
#define __ATTRIB_PACK
|
||||
#define __ATTRIB_PRINTF
|
||||
#define __ATTRIB_NORETURN
|
||||
#ifndef INLINE
|
||||
#define INLINE __inline
|
||||
#endif
|
||||
#endif /* End __GNUC__ */
|
||||
|
||||
#define PREPACK
|
||||
#define POSTPACK __ATTRIB_PACK
|
||||
|
||||
/*
|
||||
* Endianes macros
|
||||
*/
|
||||
#define A_BE2CPU8(x) ntohb(x)
|
||||
#define A_BE2CPU16(x) ntohs(x)
|
||||
#define A_BE2CPU32(x) ntohl(x)
|
||||
|
||||
#define A_LE2CPU8(x) (x)
|
||||
#define A_LE2CPU16(x) (x)
|
||||
#define A_LE2CPU32(x) (x)
|
||||
|
||||
#define A_CPU2BE8(x) htonb(x)
|
||||
#define A_CPU2BE16(x) htons(x)
|
||||
#define A_CPU2BE32(x) htonl(x)
|
||||
|
||||
#define A_MEMCPY(dst, src, len) memcpy((A_UINT8 *)(dst), (src), (len))
|
||||
#define A_MEMZERO(addr, len) memset(addr, 0, len)
|
||||
#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len))
|
||||
#define A_MALLOC(size) kmalloc((size), GFP_KERNEL)
|
||||
#define A_MALLOC_NOWAIT(size) kmalloc((size), GFP_ATOMIC)
|
||||
#define A_FREE(addr) kfree(addr)
|
||||
#define A_PRINTF(args...) printk(args)
|
||||
|
||||
/* Mutual Exclusion */
|
||||
typedef spinlock_t A_MUTEX_T;
|
||||
#define A_MUTEX_INIT(mutex) spin_lock_init(mutex)
|
||||
#define A_MUTEX_LOCK(mutex) spin_lock_bh(mutex)
|
||||
#define A_MUTEX_UNLOCK(mutex) spin_unlock_bh(mutex)
|
||||
#define A_IS_MUTEX_VALID(mutex) TRUE /* okay to return true, since A_MUTEX_DELETE does nothing */
|
||||
#define A_MUTEX_DELETE(mutex) /* spin locks are not kernel resources so nothing to free.. */
|
||||
|
||||
/* Get current time in ms adding a constant offset (in ms) */
|
||||
#define A_GET_MS(offset) \
|
||||
(jiffies + ((offset) / 1000) * HZ)
|
||||
|
||||
/*
|
||||
* Timer Functions
|
||||
*/
|
||||
#define A_MDELAY(msecs) mdelay(msecs)
|
||||
typedef struct timer_list A_TIMER;
|
||||
|
||||
#define A_INIT_TIMER(pTimer, pFunction, pArg) do { \
|
||||
init_timer(pTimer); \
|
||||
(pTimer)->function = (pFunction); \
|
||||
(pTimer)->data = (unsigned long)(pArg); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Start a Timer that elapses after 'periodMSec' milli-seconds
|
||||
* Support is provided for a one-shot timer. The 'repeatFlag' is
|
||||
* ignored.
|
||||
*/
|
||||
#define A_TIMEOUT_MS(pTimer, periodMSec, repeatFlag) do { \
|
||||
if (repeatFlag) { \
|
||||
printk("\n" __FILE__ ":%d: Timer Repeat requested\n",__LINE__); \
|
||||
panic("Timer Repeat"); \
|
||||
} \
|
||||
mod_timer((pTimer), jiffies + HZ * (periodMSec) / 1000); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Cancel the Timer.
|
||||
*/
|
||||
#define A_UNTIMEOUT(pTimer) do { \
|
||||
del_timer((pTimer)); \
|
||||
} while (0)
|
||||
|
||||
#define A_DELETE_TIMER(pTimer) do { \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Wait Queue related functions
|
||||
*/
|
||||
typedef wait_queue_head_t A_WAITQUEUE_HEAD;
|
||||
#define A_INIT_WAITQUEUE_HEAD(head) init_waitqueue_head(head)
|
||||
#ifndef wait_event_interruptible_timeout
|
||||
#define __wait_event_interruptible_timeout(wq, condition, ret) \
|
||||
do { \
|
||||
wait_queue_t __wait; \
|
||||
init_waitqueue_entry(&__wait, current); \
|
||||
\
|
||||
add_wait_queue(&wq, &__wait); \
|
||||
for (;;) { \
|
||||
set_current_state(TASK_INTERRUPTIBLE); \
|
||||
if (condition) \
|
||||
break; \
|
||||
if (!signal_pending(current)) { \
|
||||
ret = schedule_timeout(ret); \
|
||||
if (!ret) \
|
||||
break; \
|
||||
continue; \
|
||||
} \
|
||||
ret = -ERESTARTSYS; \
|
||||
break; \
|
||||
} \
|
||||
current->state = TASK_RUNNING; \
|
||||
remove_wait_queue(&wq, &__wait); \
|
||||
} while (0)
|
||||
|
||||
#define wait_event_interruptible_timeout(wq, condition, timeout) \
|
||||
({ \
|
||||
long __ret = timeout; \
|
||||
if (!(condition)) \
|
||||
__wait_event_interruptible_timeout(wq, condition, __ret); \
|
||||
__ret; \
|
||||
})
|
||||
#endif /* wait_event_interruptible_timeout */
|
||||
|
||||
#define A_WAIT_EVENT_INTERRUPTIBLE_TIMEOUT(head, condition, timeout) do { \
|
||||
wait_event_interruptible_timeout(head, condition, timeout); \
|
||||
} while (0)
|
||||
|
||||
#define A_WAKE_UP(head) wake_up(head)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define A_ASSERT(expr) \
|
||||
if (!(expr)) { \
|
||||
printk(KERN_ALERT "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
|
||||
panic(#expr); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define A_ASSERT(expr)
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* Initialization of the network buffer subsystem
|
||||
*/
|
||||
#define A_NETBUF_INIT()
|
||||
|
||||
/*
|
||||
* Network buffer queue support
|
||||
*/
|
||||
typedef struct sk_buff_head A_NETBUF_QUEUE_T;
|
||||
|
||||
#define A_NETBUF_QUEUE_INIT(q) \
|
||||
a_netbuf_queue_init(q)
|
||||
|
||||
#define A_NETBUF_ENQUEUE(q, pkt) \
|
||||
a_netbuf_enqueue((q), (pkt))
|
||||
#define A_NETBUF_PREQUEUE(q, pkt) \
|
||||
a_netbuf_prequeue((q), (pkt))
|
||||
#define A_NETBUF_DEQUEUE(q) \
|
||||
(a_netbuf_dequeue(q))
|
||||
#define A_NETBUF_QUEUE_SIZE(q) \
|
||||
a_netbuf_queue_size(q)
|
||||
#define A_NETBUF_QUEUE_EMPTY(q) \
|
||||
a_netbuf_queue_empty(q)
|
||||
|
||||
/*
|
||||
* Network buffer support
|
||||
*/
|
||||
#define A_NETBUF_ALLOC(size) \
|
||||
a_netbuf_alloc(size)
|
||||
#define A_NETBUF_ALLOC_RAW(size) \
|
||||
a_netbuf_alloc_raw(size)
|
||||
#define A_NETBUF_FREE(bufPtr) \
|
||||
a_netbuf_free(bufPtr)
|
||||
#define A_NETBUF_DATA(bufPtr) \
|
||||
a_netbuf_to_data(bufPtr)
|
||||
#define A_NETBUF_LEN(bufPtr) \
|
||||
a_netbuf_to_len(bufPtr)
|
||||
#define A_NETBUF_PUSH(bufPtr, len) \
|
||||
a_netbuf_push(bufPtr, len)
|
||||
#define A_NETBUF_PUT(bufPtr, len) \
|
||||
a_netbuf_put(bufPtr, len)
|
||||
#define A_NETBUF_TRIM(bufPtr,len) \
|
||||
a_netbuf_trim(bufPtr, len)
|
||||
#define A_NETBUF_PULL(bufPtr, len) \
|
||||
a_netbuf_pull(bufPtr, len)
|
||||
#define A_NETBUF_HEADROOM(bufPtr)\
|
||||
a_netbuf_headroom(bufPtr)
|
||||
#define A_NETBUF_SETLEN(bufPtr,len) \
|
||||
a_netbuf_setlen(bufPtr, len)
|
||||
|
||||
/* Add data to end of a buffer */
|
||||
#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \
|
||||
a_netbuf_put_data(bufPtr, srcPtr, len)
|
||||
|
||||
/* Add data to start of the buffer */
|
||||
#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \
|
||||
a_netbuf_push_data(bufPtr, srcPtr, len)
|
||||
|
||||
/* Remove data at start of the buffer */
|
||||
#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \
|
||||
a_netbuf_pull_data(bufPtr, dstPtr, len)
|
||||
|
||||
/* Remove data from the end of the buffer */
|
||||
#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \
|
||||
a_netbuf_trim_data(bufPtr, dstPtr, len)
|
||||
|
||||
/* View data as "size" contiguous bytes of type "t" */
|
||||
#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \
|
||||
(t )( ((struct skbuf *)(bufPtr))->data)
|
||||
|
||||
/* return the beginning of the headroom for the buffer */
|
||||
#define A_NETBUF_HEAD(bufPtr) \
|
||||
((((struct sk_buff *)(bufPtr))->head))
|
||||
|
||||
/*
|
||||
* OS specific network buffer access routines
|
||||
*/
|
||||
void *a_netbuf_alloc(int size);
|
||||
void *a_netbuf_alloc_raw(int size);
|
||||
void a_netbuf_free(void *bufPtr);
|
||||
void *a_netbuf_to_data(void *bufPtr);
|
||||
A_UINT32 a_netbuf_to_len(void *bufPtr);
|
||||
A_STATUS a_netbuf_push(void *bufPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_put(void *bufPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_pull(void *bufPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_trim(void *bufPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len);
|
||||
A_STATUS a_netbuf_setlen(void *bufPtr, A_INT32 len);
|
||||
A_INT32 a_netbuf_headroom(void *bufPtr);
|
||||
void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt);
|
||||
void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt);
|
||||
void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q);
|
||||
int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q);
|
||||
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
|
||||
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
|
||||
void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q);
|
||||
|
||||
/*
|
||||
* Kernel v.s User space functions
|
||||
*/
|
||||
A_UINT32 a_copy_to_user(void *to, const void *from, A_UINT32 n);
|
||||
A_UINT32 a_copy_from_user(void *to, const void *from, A_UINT32 n);
|
||||
|
||||
#else /* __KERNEL__ */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __ATTRIB_PACK __attribute__ ((packed))
|
||||
#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
|
||||
#define __ATTRIB_NORETURN __attribute__ ((noreturn))
|
||||
#ifndef INLINE
|
||||
#define INLINE __inline__
|
||||
#endif
|
||||
#else /* Not GCC */
|
||||
#define __ATTRIB_PACK
|
||||
#define __ATTRIB_PRINTF
|
||||
#define __ATTRIB_NORETURN
|
||||
#ifndef INLINE
|
||||
#define INLINE __inline
|
||||
#endif
|
||||
#endif /* End __GNUC__ */
|
||||
|
||||
#define PREPACK
|
||||
#define POSTPACK __ATTRIB_PACK
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _OSAPI_LINUX_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,657 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hif.h"
|
||||
#include "bmi.h"
|
||||
#include "htc_api.h"
|
||||
#include "bmi_internal.h"
|
||||
|
||||
/*
|
||||
Although we had envisioned BMI to run on top of HTC, this is not what the
|
||||
final implementation boiled down to on dragon. Its a part of BSP and does
|
||||
not use the HTC protocol either. On the host side, however, we were still
|
||||
living with the original idea. I think the time has come to accept the truth
|
||||
and separate it from HTC which has been carrying BMI's burden all this while.
|
||||
It shall make HTC state machine relatively simpler
|
||||
*/
|
||||
|
||||
/* APIs visible to the driver */
|
||||
void
|
||||
BMIInit(void)
|
||||
{
|
||||
bmiDone = FALSE;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIDone(HIF_DEVICE *device)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT32 cid;
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device));
|
||||
bmiDone = TRUE;
|
||||
cid = BMI_DONE;
|
||||
|
||||
status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n"));
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIGetTargetInfo(HIF_DEVICE *device, struct bmi_target_info *targ_info)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT32 cid;
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device));
|
||||
cid = BMI_GET_TARGET_INFO;
|
||||
|
||||
status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_ver,
|
||||
sizeof(targ_info->target_ver));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
if (targ_info->target_ver == TARGET_VERSION_SENTINAL) {
|
||||
/* Determine how many bytes are in the Target's targ_info */
|
||||
status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_info_byte_count,
|
||||
sizeof(targ_info->target_info_byte_count));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Target's targ_info doesn't match the Host's targ_info.
|
||||
* We need to do some backwards compatibility work to make this OK.
|
||||
*/
|
||||
A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info));
|
||||
|
||||
/* Read the remainder of the targ_info */
|
||||
status = bmiBufferReceive(device,
|
||||
((A_UCHAR *)targ_info)+sizeof(targ_info->target_info_byte_count),
|
||||
sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n",
|
||||
targ_info->target_info_byte_count));
|
||||
return A_ERROR;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Target must be an AR6001 whose firmware does not
|
||||
* support BMI_GET_TARGET_INFO. Construct the data
|
||||
* that it would have sent.
|
||||
*/
|
||||
targ_info->target_info_byte_count = sizeof(targ_info);
|
||||
targ_info->target_type = TARGET_TYPE_AR6001;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
|
||||
targ_info->target_ver, targ_info->target_type));
|
||||
printk("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
|
||||
targ_info->target_ver, targ_info->target_type);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIReadMemory(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
A_UINT32 remaining, rxlen;
|
||||
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)];
|
||||
memset (&data, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
|
||||
device, address, length));
|
||||
|
||||
cid = BMI_READ_MEMORY;
|
||||
|
||||
remaining = length;
|
||||
|
||||
while (remaining)
|
||||
{
|
||||
rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX;
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
A_MEMCPY(&data[offset], &rxlen, sizeof(rxlen));
|
||||
offset += sizeof(length);
|
||||
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
status = bmiBufferReceive(device, data, rxlen);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
A_MEMCPY(&buffer[length - remaining], data, rxlen);
|
||||
remaining -= rxlen; address += rxlen;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIWriteMemory(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
A_UINT32 remaining, txlen;
|
||||
const A_UINT32 header = sizeof(cid) + sizeof(address) + sizeof(length);
|
||||
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)];
|
||||
memset (&data, 0, header);
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
|
||||
device, address, length));
|
||||
|
||||
cid = BMI_WRITE_MEMORY;
|
||||
|
||||
remaining = length;
|
||||
while (remaining)
|
||||
{
|
||||
txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
|
||||
remaining : (BMI_DATASZ_MAX - header);
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
A_MEMCPY(&data[offset], &txlen, sizeof(txlen));
|
||||
offset += sizeof(txlen);
|
||||
A_MEMCPY(&data[offset], &buffer[length - remaining], txlen);
|
||||
offset += txlen;
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
remaining -= txlen; address += txlen;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n"));
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIExecute(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 *param)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(address) + sizeof(*param)];
|
||||
memset (&data, 0, sizeof(cid) + sizeof(address) + sizeof(*param));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
|
||||
device, address, *param));
|
||||
|
||||
cid = BMI_EXECUTE;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
A_MEMCPY(&data[offset], param, sizeof(*param));
|
||||
offset += sizeof(*param);
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
status = bmiBufferReceive(device, data, sizeof(*param));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
A_MEMCPY(param, data, sizeof(*param));
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMISetAppStart(HIF_DEVICE *device,
|
||||
A_UINT32 address)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(address)];
|
||||
memset (&data, 0, sizeof(cid) + sizeof(address));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n",
|
||||
device, address));
|
||||
|
||||
cid = BMI_SET_APP_START;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIReadSOCRegister(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 *param)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(address)];
|
||||
memset (&data, 0, sizeof(cid) + sizeof(address));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n",
|
||||
device, address));
|
||||
|
||||
cid = BMI_READ_SOC_REGISTER;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
status = bmiBufferReceive(device, data, sizeof(*param));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
A_MEMCPY(param, data, sizeof(*param));
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIWriteSOCRegister(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 param)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(address) + sizeof(param)];
|
||||
|
||||
memset (&data, 0, sizeof(cid) + sizeof(address) + sizeof(param));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
|
||||
device, address, param));
|
||||
|
||||
cid = BMI_WRITE_SOC_REGISTER;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &address, sizeof(address));
|
||||
offset += sizeof(address);
|
||||
A_MEMCPY(&data[offset], ¶m, sizeof(param));
|
||||
offset += sizeof(param);
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchInstall(HIF_DEVICE *device,
|
||||
A_UINT32 ROM_addr,
|
||||
A_UINT32 RAM_addr,
|
||||
A_UINT32 nbytes,
|
||||
A_UINT32 do_activate,
|
||||
A_UINT32 *rompatch_id)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
|
||||
sizeof(nbytes) + sizeof(do_activate)];
|
||||
|
||||
memset (&data, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
|
||||
sizeof(nbytes) + sizeof(do_activate));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n",
|
||||
device, ROM_addr, RAM_addr, nbytes, do_activate));
|
||||
|
||||
cid = BMI_ROMPATCH_INSTALL;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &ROM_addr, sizeof(ROM_addr));
|
||||
offset += sizeof(ROM_addr);
|
||||
A_MEMCPY(&data[offset], &RAM_addr, sizeof(RAM_addr));
|
||||
offset += sizeof(RAM_addr);
|
||||
A_MEMCPY(&data[offset], &nbytes, sizeof(nbytes));
|
||||
offset += sizeof(nbytes);
|
||||
A_MEMCPY(&data[offset], &do_activate, sizeof(do_activate));
|
||||
offset += sizeof(do_activate);
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
status = bmiBufferReceive(device, (A_UCHAR *)rompatch_id, sizeof(*rompatch_id));
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchUninstall(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_id)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[sizeof(cid) + sizeof(rompatch_id)];
|
||||
memset (&data, 0, sizeof(cid) + sizeof(rompatch_id));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n",
|
||||
device, rompatch_id));
|
||||
|
||||
cid = BMI_ROMPATCH_UNINSTALL;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &rompatch_id, sizeof(rompatch_id));
|
||||
offset += sizeof(rompatch_id);
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
static A_STATUS
|
||||
_BMIrompatchChangeActivation(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_count,
|
||||
A_UINT32 *rompatch_list,
|
||||
A_UINT32 do_activate)
|
||||
{
|
||||
A_UINT32 cid;
|
||||
A_STATUS status;
|
||||
A_UINT32 offset;
|
||||
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)];
|
||||
A_UINT32 length;
|
||||
|
||||
memset (&data, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count));
|
||||
|
||||
if (bmiDone) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
||||
("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n",
|
||||
device, rompatch_count));
|
||||
|
||||
cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE;
|
||||
|
||||
offset = 0;
|
||||
A_MEMCPY(&data[offset], &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
A_MEMCPY(&data[offset], &rompatch_count, sizeof(rompatch_count));
|
||||
offset += sizeof(rompatch_count);
|
||||
length = rompatch_count * sizeof(*rompatch_list);
|
||||
A_MEMCPY(&data[offset], rompatch_list, length);
|
||||
offset += length;
|
||||
status = bmiBufferSend(device, data, offset);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n"));
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchActivate(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_count,
|
||||
A_UINT32 *rompatch_list)
|
||||
{
|
||||
return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1);
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchDeactivate(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_count,
|
||||
A_UINT32 *rompatch_list)
|
||||
{
|
||||
return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0);
|
||||
}
|
||||
|
||||
/* BMI Access routines */
|
||||
A_STATUS
|
||||
bmiBufferSend(HIF_DEVICE *device,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT32 timeout;
|
||||
A_UINT32 address;
|
||||
static A_UINT32 cmdCredits;
|
||||
A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
|
||||
|
||||
HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
|
||||
&mboxAddress, sizeof(mboxAddress));
|
||||
|
||||
cmdCredits = 0;
|
||||
timeout = BMI_COMMUNICATION_TIMEOUT;
|
||||
|
||||
while(timeout-- && !cmdCredits) {
|
||||
/* Read the counter register to get the command credits */
|
||||
address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
|
||||
/* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause
|
||||
* a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to
|
||||
* make all HIF accesses 4-byte aligned */
|
||||
status = HIFReadWrite(device, address, (A_UINT8 *)&cmdCredits, 4,
|
||||
HIF_RD_SYNC_BYTE_INC, NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
/* the counter is only 8=bits, ignore anything in the upper 3 bytes */
|
||||
cmdCredits &= 0xFF;
|
||||
}
|
||||
|
||||
if (cmdCredits) {
|
||||
address = mboxAddress[ENDPOINT1];
|
||||
status = HIFReadWrite(device, address, buffer, length,
|
||||
HIF_WR_SYNC_BYTE_INC, NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
bmiBufferReceive(HIF_DEVICE *device,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT32 address;
|
||||
A_UINT32 timeout;
|
||||
static A_UINT32 cmdCredits;
|
||||
A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
|
||||
|
||||
HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
|
||||
&mboxAddress, sizeof(mboxAddress));
|
||||
|
||||
cmdCredits = 0;
|
||||
timeout = BMI_COMMUNICATION_TIMEOUT;
|
||||
while(timeout-- && !cmdCredits) {
|
||||
/* Read the counter register to get the command credits */
|
||||
address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1;
|
||||
/* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing,
|
||||
* we can read this counter multiple times using a non-incrementing address mode.
|
||||
* The rationale here is to make all HIF accesses a multiple of 4 bytes */
|
||||
status = HIFReadWrite(device, address, (A_UINT8 *)&cmdCredits, sizeof(cmdCredits),
|
||||
HIF_RD_SYNC_BYTE_FIX, NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
/* we did a 4-byte read to the same count register so mask off upper bytes */
|
||||
cmdCredits &= 0xFF;
|
||||
status = A_ERROR;
|
||||
}
|
||||
|
||||
if (cmdCredits) {
|
||||
address = mboxAddress[ENDPOINT1];
|
||||
status = HIFReadWrite(device, address, buffer, length,
|
||||
HIF_RD_SYNC_BYTE_INC, NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Communication timeout\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef BMI_INTERNAL_H
|
||||
#define BMI_INTERNAL_H
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "a_debug.h"
|
||||
#include "AR6Khwreg.h"
|
||||
#include "bmi_msg.h"
|
||||
|
||||
#define BMI_COMMUNICATION_TIMEOUT 100000
|
||||
|
||||
/* ------ Global Variable Declarations ------- */
|
||||
A_BOOL bmiDone;
|
||||
|
||||
A_STATUS
|
||||
bmiBufferSend(HIF_DEVICE *device,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length);
|
||||
|
||||
A_STATUS
|
||||
bmiBufferReceive(HIF_DEVICE *device,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
* @file: hif.c
|
||||
*
|
||||
* @abstract: HIF layer reference implementation for Atheros SDIO stack
|
||||
*
|
||||
* @notice: Copyright (c) 2004-2006 Atheros Communications 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hif_internal.h"
|
||||
|
||||
/* ------ Static Variables ------ */
|
||||
|
||||
/* ------ Global Variable Declarations ------- */
|
||||
SD_PNP_INFO Ids[] = {
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xB,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xA,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x9,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x8,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x0,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x1,
|
||||
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
|
||||
.SDIO_FunctionClass = FUNCTION_CLASS,
|
||||
.SDIO_FunctionNo = 1
|
||||
},
|
||||
{
|
||||
} //list is null termintaed
|
||||
};
|
||||
|
||||
TARGET_FUNCTION_CONTEXT FunctionContext = {
|
||||
.function.Version = CT_SDIO_STACK_VERSION_CODE,
|
||||
.function.pName = "sdio_wlan",
|
||||
.function.MaxDevices = 1,
|
||||
.function.NumDevices = 0,
|
||||
.function.pIds = Ids,
|
||||
.function.pProbe = hifDeviceInserted,
|
||||
.function.pRemove = hifDeviceRemoved,
|
||||
.function.pSuspend = NULL,
|
||||
.function.pResume = NULL,
|
||||
.function.pWake = NULL,
|
||||
.function.pContext = &FunctionContext,
|
||||
};
|
||||
|
||||
HIF_DEVICE hifDevice[HIF_MAX_DEVICES];
|
||||
HTC_CALLBACKS htcCallbacks;
|
||||
BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM];
|
||||
static BUS_REQUEST *s_busRequestFreeQueue = NULL;
|
||||
OS_CRITICALSECTION lock;
|
||||
extern A_UINT32 onebitmode;
|
||||
extern A_UINT32 busspeedlow;
|
||||
|
||||
#ifdef DEBUG
|
||||
extern A_UINT32 debughif;
|
||||
#define ATH_DEBUG_ERROR 1
|
||||
#define ATH_DEBUG_WARN 2
|
||||
#define ATH_DEBUG_TRACE 3
|
||||
#define _AR_DEBUG_PRINTX_ARG(arg...) arg
|
||||
#define AR_DEBUG_PRINTF(lvl, args)\
|
||||
{if (lvl <= debughif)\
|
||||
A_PRINTF(KERN_ALERT _AR_DEBUG_PRINTX_ARG args);\
|
||||
}
|
||||
#else
|
||||
#define AR_DEBUG_PRINTF(lvl, args)
|
||||
#endif
|
||||
|
||||
static BUS_REQUEST *hifAllocateBusRequest(void);
|
||||
static void hifFreeBusRequest(BUS_REQUEST *busrequest);
|
||||
static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper);
|
||||
static void ResetAllCards(void);
|
||||
|
||||
/* ------ Functions ------ */
|
||||
int HIFInit(HTC_CALLBACKS *callbacks)
|
||||
{
|
||||
SDIO_STATUS status;
|
||||
DBG_ASSERT(callbacks != NULL);
|
||||
|
||||
/* Store the callback and event handlers */
|
||||
htcCallbacks.deviceInsertedHandler = callbacks->deviceInsertedHandler;
|
||||
htcCallbacks.deviceRemovedHandler = callbacks->deviceRemovedHandler;
|
||||
htcCallbacks.deviceSuspendHandler = callbacks->deviceSuspendHandler;
|
||||
htcCallbacks.deviceResumeHandler = callbacks->deviceResumeHandler;
|
||||
htcCallbacks.deviceWakeupHandler = callbacks->deviceWakeupHandler;
|
||||
htcCallbacks.rwCompletionHandler = callbacks->rwCompletionHandler;
|
||||
htcCallbacks.dsrHandler = callbacks->dsrHandler;
|
||||
|
||||
CriticalSectionInit(&lock);
|
||||
|
||||
/* Register with bus driver core */
|
||||
status = SDIO_RegisterFunction(&FunctionContext.function);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
HIFReadWrite(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length,
|
||||
A_UINT32 request,
|
||||
void *context)
|
||||
{
|
||||
A_UINT8 rw;
|
||||
A_UINT8 mode;
|
||||
A_UINT8 funcNo;
|
||||
A_UINT8 opcode;
|
||||
A_UINT16 count;
|
||||
SDREQUEST *sdrequest;
|
||||
SDIO_STATUS sdiostatus;
|
||||
BUS_REQUEST *busrequest;
|
||||
A_STATUS status = A_OK;
|
||||
|
||||
DBG_ASSERT(device != NULL);
|
||||
DBG_ASSERT(device->handle != NULL);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
|
||||
|
||||
do {
|
||||
busrequest = hifAllocateBusRequest();
|
||||
if (busrequest == NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF Unable to allocate bus request\n"));
|
||||
status = A_NO_RESOURCE;
|
||||
break;
|
||||
}
|
||||
|
||||
sdrequest = busrequest->request;
|
||||
busrequest->context = context;
|
||||
|
||||
sdrequest->pDataBuffer = buffer;
|
||||
if (request & HIF_SYNCHRONOUS) {
|
||||
sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS;
|
||||
sdrequest->pCompleteContext = NULL;
|
||||
sdrequest->pCompletion = NULL;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Synchronous\n"));
|
||||
} else if (request & HIF_ASYNCHRONOUS) {
|
||||
sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS |
|
||||
SDREQ_FLAGS_TRANS_ASYNC;
|
||||
sdrequest->pCompleteContext = busrequest;
|
||||
sdrequest->pCompletion = hifRWCompletionHandler;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Asynchronous\n"));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Invalid execution mode: 0x%08x\n", request));
|
||||
status = A_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (request & HIF_EXTENDED_IO) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Command type: CMD53\n"));
|
||||
sdrequest->Command = CMD53;
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Invalid command type: 0x%08x\n", request));
|
||||
status = A_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (request & HIF_BLOCK_BASIS) {
|
||||
mode = CMD53_BLOCK_BASIS;
|
||||
sdrequest->BlockLen = HIF_MBOX_BLOCK_SIZE;
|
||||
sdrequest->BlockCount = length / HIF_MBOX_BLOCK_SIZE;
|
||||
count = sdrequest->BlockCount;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Block mode (BlockLen: %d, BlockCount: %d)\n",
|
||||
sdrequest->BlockLen, sdrequest->BlockCount));
|
||||
} else if (request & HIF_BYTE_BASIS) {
|
||||
mode = CMD53_BYTE_BASIS;
|
||||
sdrequest->BlockLen = length;
|
||||
sdrequest->BlockCount = 1;
|
||||
count = sdrequest->BlockLen;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Byte mode (BlockLen: %d, BlockCount: %d)\n",
|
||||
sdrequest->BlockLen, sdrequest->BlockCount));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Invalid data mode: 0x%08x\n", request));
|
||||
status = A_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* useful for checking register accesses */
|
||||
if (length & 0x3) {
|
||||
A_PRINTF(KERN_ALERT"HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
|
||||
request & HIF_WRITE ? "write":"read", address, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((address >= HIF_MBOX_START_ADDR(0)) &&
|
||||
(address <= HIF_MBOX_END_ADDR(3)))
|
||||
{
|
||||
|
||||
DBG_ASSERT(length <= HIF_MBOX_WIDTH);
|
||||
|
||||
/*
|
||||
* Mailbox write. Adjust the address so that the last byte
|
||||
* falls on the EOM address.
|
||||
*/
|
||||
address += (HIF_MBOX_WIDTH - length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (request & HIF_WRITE) {
|
||||
rw = CMD53_WRITE;
|
||||
sdrequest->Flags |= SDREQ_FLAGS_DATA_WRITE;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Write\n"));
|
||||
} else if (request & HIF_READ) {
|
||||
rw = CMD53_READ;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Read\n"));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Invalid direction: 0x%08x\n", request));
|
||||
status = A_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (request & HIF_FIXED_ADDRESS) {
|
||||
opcode = CMD53_FIXED_ADDRESS;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Fixed\n"));
|
||||
} else if (request & HIF_INCREMENTAL_ADDRESS) {
|
||||
opcode = CMD53_INCR_ADDRESS;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Incremental\n"));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Invalid address mode: 0x%08x\n", request));
|
||||
status = A_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
funcNo = SDDEVICE_GET_SDIO_FUNCNO(device->handle);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Function number: %d\n", funcNo));
|
||||
SDIO_SET_CMD53_ARG(sdrequest->Argument, rw, funcNo,
|
||||
mode, opcode, address, count);
|
||||
|
||||
/* Send the command out */
|
||||
sdiostatus = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest);
|
||||
|
||||
if (!SDIO_SUCCESS(sdiostatus)) {
|
||||
status = A_ERROR;
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status) || (request & HIF_SYNCHRONOUS)) {
|
||||
if (busrequest != NULL) {
|
||||
hifFreeBusRequest(busrequest);
|
||||
}
|
||||
}
|
||||
|
||||
if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) {
|
||||
/* call back async handler on failure */
|
||||
htcCallbacks.rwCompletionHandler(context, status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
|
||||
void *config, A_UINT32 configLen)
|
||||
{
|
||||
A_UINT32 count;
|
||||
|
||||
switch(opcode) {
|
||||
case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
|
||||
((A_UINT32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
|
||||
((A_UINT32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
|
||||
((A_UINT32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
|
||||
((A_UINT32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case HIF_DEVICE_GET_MBOX_ADDR:
|
||||
for (count = 0; count < 4; count ++) {
|
||||
((A_UINT32 *)config)[count] = HIF_MBOX_START_ADDR(count);
|
||||
}
|
||||
break;
|
||||
case HIF_DEVICE_GET_IRQ_PROC_MODE:
|
||||
/* the SDIO stack allows the interrupts to be processed either way, ASYNC or SYNC */
|
||||
*((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_ASYNC_SYNC;
|
||||
break;
|
||||
default:
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
|
||||
("Unsupported configuration opcode: %d\n", opcode));
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HIFShutDownDevice(HIF_DEVICE *device)
|
||||
{
|
||||
A_UINT8 data;
|
||||
A_UINT32 count;
|
||||
SDIO_STATUS status;
|
||||
SDCONFIG_BUS_MODE_DATA busSettings;
|
||||
SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
|
||||
|
||||
if (device != NULL) {
|
||||
DBG_ASSERT(device->handle != NULL);
|
||||
|
||||
/* Remove the allocated current if any */
|
||||
status = SDLIB_IssueConfig(device->handle,
|
||||
SDCONFIG_FUNC_FREE_SLOT_CURRENT, NULL, 0);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
|
||||
/* Disable the card */
|
||||
fData.EnableFlags = SDCONFIG_DISABLE_FUNC;
|
||||
fData.TimeOut = 1;
|
||||
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ENABLE_DISABLE,
|
||||
&fData, sizeof(fData));
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
|
||||
/* Perform a soft I/O reset */
|
||||
data = SDIO_IO_RESET;
|
||||
status = SDLIB_IssueCMD52(device->handle, 0, SDIO_IO_ABORT_REG,
|
||||
&data, 1, 1);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
|
||||
/*
|
||||
* WAR - Codetelligence driver does not seem to shutdown correctly in 1
|
||||
* bit mode. By default it configures the HC in the 4 bit. Its later in
|
||||
* our driver that we switch to 1 bit mode. If we try to shutdown, the
|
||||
* driver hangs so we revert to 4 bit mode, to be transparent to the
|
||||
* underlying bus driver.
|
||||
*/
|
||||
if (onebitmode) {
|
||||
ZERO_OBJECT(busSettings);
|
||||
busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(device->handle);
|
||||
SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
|
||||
SDCONFIG_BUS_WIDTH_4_BIT);
|
||||
|
||||
/* Issue config request to change the bus width to 4 bit */
|
||||
status = SDLIB_IssueConfig(device->handle, SDCONFIG_BUS_MODE_CTRL,
|
||||
&busSettings,
|
||||
sizeof(SDCONFIG_BUS_MODE_DATA));
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
}
|
||||
|
||||
/* Free the bus requests */
|
||||
for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
|
||||
SDDeviceFreeRequest(device->handle, busRequest[count].request);
|
||||
}
|
||||
/* Clean up the queue */
|
||||
s_busRequestFreeQueue = NULL;
|
||||
} else {
|
||||
/* since we are unloading the driver anyways, reset all cards in case the SDIO card
|
||||
* is externally powered and we are unloading the SDIO stack. This avoids the problem when
|
||||
* the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
|
||||
* enumerated */
|
||||
ResetAllCards();
|
||||
/* Unregister with bus driver core */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Unregistering with the bus driver\n"));
|
||||
status = SDIO_UnregisterFunction(&FunctionContext.function);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hifRWCompletionHandler(SDREQUEST *request)
|
||||
{
|
||||
A_STATUS status;
|
||||
void *context;
|
||||
BUS_REQUEST *busrequest;
|
||||
|
||||
if (SDIO_SUCCESS(request->Status)) {
|
||||
status = A_OK;
|
||||
} else {
|
||||
status = A_ERROR;
|
||||
}
|
||||
|
||||
DBG_ASSERT(status == A_OK);
|
||||
busrequest = (BUS_REQUEST *) request->pCompleteContext;
|
||||
context = (void *) busrequest->context;
|
||||
/* free the request before calling the callback, in case the
|
||||
* callback submits another request, this guarantees that
|
||||
* there is at least 1 free request available everytime the callback
|
||||
* is invoked */
|
||||
hifFreeBusRequest(busrequest);
|
||||
htcCallbacks.rwCompletionHandler(context, status);
|
||||
}
|
||||
|
||||
void
|
||||
hifIRQHandler(void *context)
|
||||
{
|
||||
A_STATUS status;
|
||||
HIF_DEVICE *device;
|
||||
|
||||
device = (HIF_DEVICE *)context;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
|
||||
status = htcCallbacks.dsrHandler(device->htc_handle);
|
||||
DBG_ASSERT(status == A_OK);
|
||||
}
|
||||
|
||||
BOOL
|
||||
hifDeviceInserted(SDFUNCTION *function, SDDEVICE *handle)
|
||||
{
|
||||
BOOL enabled;
|
||||
A_UINT8 data;
|
||||
A_UINT32 count;
|
||||
HIF_DEVICE *device;
|
||||
SDIO_STATUS status;
|
||||
A_UINT16 maxBlocks;
|
||||
A_UINT16 maxBlockSize;
|
||||
SDCONFIG_BUS_MODE_DATA busSettings;
|
||||
SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
|
||||
TARGET_FUNCTION_CONTEXT *functionContext;
|
||||
SDCONFIG_FUNC_SLOT_CURRENT_DATA slotCurrent;
|
||||
SD_BUSCLOCK_RATE currentBusClock;
|
||||
|
||||
DBG_ASSERT(function != NULL);
|
||||
DBG_ASSERT(handle != NULL);
|
||||
|
||||
device = addHifDevice(handle);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
|
||||
functionContext = (TARGET_FUNCTION_CONTEXT *)function->pContext;
|
||||
|
||||
/*
|
||||
* Issue commands to get the manufacturer ID and stuff and compare it
|
||||
* against the rev Id derived from the ID registered during the
|
||||
* initialization process. Report the device only in the case there
|
||||
* is a match. In the case od SDIO, the bus driver has already queried
|
||||
* these details so we just need to use their data structures to get the
|
||||
* relevant values. Infact, the driver has already matched it against
|
||||
* the Ids that we registered with it so we dont need to the step here.
|
||||
*/
|
||||
|
||||
/* Configure the SDIO Bus Width */
|
||||
if (onebitmode) {
|
||||
data = SDIO_BUS_WIDTH_1_BIT;
|
||||
status = SDLIB_IssueCMD52(handle, 0, SDIO_BUS_IF_REG, &data, 1, 1);
|
||||
if (!SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Unable to set the bus width to 1 bit\n"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get current bus flags */
|
||||
ZERO_OBJECT(busSettings);
|
||||
|
||||
busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(handle);
|
||||
if (onebitmode) {
|
||||
SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
|
||||
SDCONFIG_BUS_WIDTH_1_BIT);
|
||||
}
|
||||
|
||||
/* get the current operating clock, the bus driver sets us up based
|
||||
* on what our CIS reports and what the host controller can handle
|
||||
* we can use this to determine whether we want to drop our clock rate
|
||||
* down */
|
||||
currentBusClock = SDDEVICE_GET_OPER_CLOCK(handle);
|
||||
busSettings.ClockRate = currentBusClock;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("HIF currently running at: %d \n",currentBusClock));
|
||||
|
||||
/* see if HIF wants to run at a lower clock speed, we may already be
|
||||
* at that lower clock speed */
|
||||
if (currentBusClock > (SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow)) {
|
||||
busSettings.ClockRate = SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
|
||||
("HIF overriding clock to %d \n",busSettings.ClockRate));
|
||||
}
|
||||
|
||||
/* Issue config request to override clock rate */
|
||||
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_CHANGE_BUS_MODE, &busSettings,
|
||||
sizeof(SDCONFIG_BUS_MODE_DATA));
|
||||
if (!SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Unable to configure the host clock\n"));
|
||||
return FALSE;
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Configured clock: %d, Maximum clock: %d\n",
|
||||
busSettings.ActualClockRate,
|
||||
SDDEVICE_GET_MAX_CLOCK(handle)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the target supports block mode. This result of this check
|
||||
* can be used to implement the HIFReadWrite API.
|
||||
*/
|
||||
if (SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle)) {
|
||||
/* Limit block size to operational block limit or card function
|
||||
capability */
|
||||
maxBlockSize = min(SDDEVICE_GET_OPER_BLOCK_LEN(handle),
|
||||
SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle));
|
||||
|
||||
/* check if the card support multi-block transfers */
|
||||
if (!(SDDEVICE_GET_SDIOCARD_CAPS(handle) & SDIO_CAPS_MULTI_BLOCK)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Byte basis only\n"));
|
||||
|
||||
/* Limit block size to max byte basis */
|
||||
maxBlockSize = min(maxBlockSize,
|
||||
(A_UINT16)SDIO_MAX_LENGTH_BYTE_BASIS);
|
||||
maxBlocks = 1;
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Multi-block capable\n"));
|
||||
maxBlocks = SDDEVICE_GET_OPER_BLOCKS(handle);
|
||||
status = SDLIB_SetFunctionBlockSize(handle, HIF_MBOX_BLOCK_SIZE);
|
||||
if (!SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Failed to set block size. Err:%d\n", status));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Bytes Per Block: %d bytes, Block Count:%d \n",
|
||||
maxBlockSize, maxBlocks));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Function does not support Block Mode!\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Allocate the slot current */
|
||||
status = SDLIB_GetDefaultOpCurrent(handle, &slotCurrent.SlotCurrent);
|
||||
if (SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Allocating Slot current: %d mA\n",
|
||||
slotCurrent.SlotCurrent));
|
||||
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ALLOC_SLOT_CURRENT,
|
||||
&slotCurrent, sizeof(slotCurrent));
|
||||
if (!SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Failed to allocate slot current %d\n", status));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the dragon function */
|
||||
count = 0;
|
||||
enabled = FALSE;
|
||||
fData.TimeOut = 1;
|
||||
fData.EnableFlags = SDCONFIG_ENABLE_FUNC;
|
||||
while ((count++ < SDWLAN_ENABLE_DISABLE_TIMEOUT) && !enabled)
|
||||
{
|
||||
/* Enable dragon */
|
||||
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ENABLE_DISABLE,
|
||||
&fData, sizeof(fData));
|
||||
if (!SDIO_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Attempting to enable the card again\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Mark the status as enabled */
|
||||
enabled = TRUE;
|
||||
}
|
||||
|
||||
/* Check if we were succesful in enabling the target */
|
||||
if (!enabled) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
|
||||
("Failed to communicate with the target\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Allocate the bus requests to be used later */
|
||||
A_MEMZERO(busRequest, sizeof(busRequest));
|
||||
for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
|
||||
if ((busRequest[count].request = SDDeviceAllocRequest(handle)) == NULL){
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate memory\n"));
|
||||
/* TODO: Free the memory that has already been allocated */
|
||||
return FALSE;
|
||||
}
|
||||
hifFreeBusRequest(&busRequest[count]);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("0x%08x = busRequest[%d].request = 0x%08x\n",
|
||||
(unsigned int) &busRequest[count], count,
|
||||
(unsigned int) busRequest[count].request));
|
||||
}
|
||||
|
||||
/* Schedule a worker to handle device inserted, this is a temporary workaround
|
||||
* to fix a deadlock if the device fails to intialize in the insertion handler
|
||||
* The failure causes the instance to shutdown the HIF layer and unregister the
|
||||
* function driver within the busdriver probe context which can deadlock
|
||||
*
|
||||
* NOTE: we cannot use the default work queue because that would block
|
||||
* SD bus request processing for all synchronous I/O. We must use a kernel
|
||||
* thread that is creating using the helper library.
|
||||
* */
|
||||
|
||||
if (SDIO_SUCCESS(SDLIB_OSCreateHelper(&device->insert_helper,
|
||||
insert_helper_func,
|
||||
device))) {
|
||||
device->helper_started = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper)
|
||||
{
|
||||
|
||||
/*
|
||||
* Adding a wait of around a second before we issue the very first
|
||||
* command to dragon. During the process of loading/unloading the
|
||||
* driver repeatedly it was observed that we get a data timeout
|
||||
* while accessing function 1 registers in the chip. The theory at
|
||||
* this point is that some initialization delay in dragon is
|
||||
* causing the SDIO state in dragon core to be not ready even after
|
||||
* the ready bit indicates that function 1 is ready. Accomodating
|
||||
* for this behavior by adding some delay in the driver before it
|
||||
* issues the first command after switching on dragon. Need to
|
||||
* investigate this a bit more - TODO
|
||||
*/
|
||||
|
||||
A_MDELAY(1000);
|
||||
/* Inform HTC */
|
||||
if ((htcCallbacks.deviceInsertedHandler(SD_GET_OS_HELPER_CONTEXT(pHelper))) != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device rejected\n"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
HIFAckInterrupt(HIF_DEVICE *device)
|
||||
{
|
||||
SDIO_STATUS status;
|
||||
DBG_ASSERT(device != NULL);
|
||||
DBG_ASSERT(device->handle != NULL);
|
||||
|
||||
/* Acknowledge our function IRQ */
|
||||
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ACK_IRQ,
|
||||
NULL, 0);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
}
|
||||
|
||||
void
|
||||
HIFUnMaskInterrupt(HIF_DEVICE *device)
|
||||
{
|
||||
SDIO_STATUS status;
|
||||
|
||||
DBG_ASSERT(device != NULL);
|
||||
DBG_ASSERT(device->handle != NULL);
|
||||
|
||||
/* Register the IRQ Handler */
|
||||
SDDEVICE_SET_IRQ_HANDLER(device->handle, hifIRQHandler, device);
|
||||
|
||||
/* Unmask our function IRQ */
|
||||
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ,
|
||||
NULL, 0);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
}
|
||||
|
||||
void HIFMaskInterrupt(HIF_DEVICE *device)
|
||||
{
|
||||
SDIO_STATUS status;
|
||||
DBG_ASSERT(device != NULL);
|
||||
DBG_ASSERT(device->handle != NULL);
|
||||
|
||||
/* Mask our function IRQ */
|
||||
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_MASK_IRQ,
|
||||
NULL, 0);
|
||||
DBG_ASSERT(SDIO_SUCCESS(status));
|
||||
|
||||
/* Unregister the IRQ Handler */
|
||||
SDDEVICE_SET_IRQ_HANDLER(device->handle, NULL, NULL);
|
||||
}
|
||||
|
||||
static BUS_REQUEST *hifAllocateBusRequest(void)
|
||||
{
|
||||
BUS_REQUEST *busrequest;
|
||||
|
||||
/* Acquire lock */
|
||||
CriticalSectionAcquire(&lock);
|
||||
|
||||
/* Remove first in list */
|
||||
if((busrequest = s_busRequestFreeQueue) != NULL)
|
||||
{
|
||||
s_busRequestFreeQueue = busrequest->next;
|
||||
}
|
||||
|
||||
/* Release lock */
|
||||
CriticalSectionRelease(&lock);
|
||||
|
||||
return busrequest;
|
||||
}
|
||||
|
||||
static void
|
||||
hifFreeBusRequest(BUS_REQUEST *busrequest)
|
||||
{
|
||||
DBG_ASSERT(busrequest != NULL);
|
||||
|
||||
/* Acquire lock */
|
||||
CriticalSectionAcquire(&lock);
|
||||
|
||||
/* Insert first in list */
|
||||
busrequest->next = s_busRequestFreeQueue;
|
||||
s_busRequestFreeQueue = busrequest;
|
||||
|
||||
/* Release lock */
|
||||
CriticalSectionRelease(&lock);
|
||||
}
|
||||
|
||||
void
|
||||
hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *handle)
|
||||
{
|
||||
A_STATUS status;
|
||||
HIF_DEVICE *device;
|
||||
DBG_ASSERT(function != NULL);
|
||||
DBG_ASSERT(handle != NULL);
|
||||
|
||||
device = getHifDevice(handle);
|
||||
status = htcCallbacks.deviceRemovedHandler(device->htc_handle, A_OK);
|
||||
|
||||
/* cleanup the helper thread */
|
||||
if (device->helper_started) {
|
||||
SDLIB_OSDeleteHelper(&device->insert_helper);
|
||||
device->helper_started = FALSE;
|
||||
}
|
||||
|
||||
delHifDevice(handle);
|
||||
DBG_ASSERT(status == A_OK);
|
||||
}
|
||||
|
||||
HIF_DEVICE *
|
||||
addHifDevice(SDDEVICE *handle)
|
||||
{
|
||||
DBG_ASSERT(handle != NULL);
|
||||
hifDevice[0].handle = handle;
|
||||
return &hifDevice[0];
|
||||
}
|
||||
|
||||
HIF_DEVICE *
|
||||
getHifDevice(SDDEVICE *handle)
|
||||
{
|
||||
DBG_ASSERT(handle != NULL);
|
||||
return &hifDevice[0];
|
||||
}
|
||||
|
||||
void
|
||||
delHifDevice(SDDEVICE *handle)
|
||||
{
|
||||
DBG_ASSERT(handle != NULL);
|
||||
hifDevice[0].handle = NULL;
|
||||
}
|
||||
|
||||
struct device*
|
||||
HIFGetOSDevice(HIF_DEVICE *device)
|
||||
{
|
||||
return &device->handle->Device->dev;
|
||||
}
|
||||
|
||||
static void ResetAllCards(void)
|
||||
{
|
||||
UINT8 data;
|
||||
SDIO_STATUS status;
|
||||
int i;
|
||||
|
||||
data = SDIO_IO_RESET;
|
||||
|
||||
/* set the I/O CARD reset bit:
|
||||
* NOTE: we are exploiting a "feature" of the SDIO core that resets the core when you
|
||||
* set the RES bit in the SDIO_IO_ABORT register. This bit however "normally" resets the
|
||||
* I/O functions leaving the SDIO core in the same state (as per SDIO spec).
|
||||
* In this design, this reset can be used to reset the SDIO core itself */
|
||||
for (i = 0; i < HIF_MAX_DEVICES; i++) {
|
||||
if (hifDevice[i].handle != NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
|
||||
("Issuing I/O Card reset for instance: %d \n",i));
|
||||
/* set the I/O Card reset bit */
|
||||
status = SDLIB_IssueCMD52(hifDevice[i].handle,
|
||||
0, /* function 0 space */
|
||||
SDIO_IO_ABORT_REG,
|
||||
&data,
|
||||
1, /* 1 byte */
|
||||
TRUE); /* write */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HIFSetHandle(void *hif_handle, void *handle)
|
||||
{
|
||||
HIF_DEVICE *device = (HIF_DEVICE *) hif_handle;
|
||||
|
||||
device->htc_handle = handle;
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
* hif2.c - HIF layer re-implementation for the Linux SDIO stack
|
||||
*
|
||||
* Copyright (C) 2008, 2009 by OpenMoko, Inc.
|
||||
* Written by Werner Almesberger <werner@openmoko.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Based on:
|
||||
*
|
||||
* @abstract: HIF layer reference implementation for Atheros SDIO stack
|
||||
* @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "hif.h"
|
||||
|
||||
|
||||
/* @@@ Hack - this wants cleaning up */
|
||||
|
||||
#ifdef CONFIG_MACH_NEO1973_GTA02
|
||||
|
||||
#include <mach/gta02-pm-wlan.h>
|
||||
|
||||
#else /* CONFIG_MACH_NEO1973_GTA02 */
|
||||
|
||||
#define gta02_wlan_query_rfkill_lock() 1
|
||||
#define gta02_wlan_set_rfkill_cb(cb, hif) ((void) cb)
|
||||
#define gta02_wlan_query_rfkill_unlock()
|
||||
#define gta02_wlan_clear_rfkill_cb()
|
||||
|
||||
#endif /* !CONFIG_MACH_NEO1973_GTA02 */
|
||||
|
||||
|
||||
/*
|
||||
* KNOWN BUGS:
|
||||
*
|
||||
* - HIF_DEVICE_IRQ_ASYNC_SYNC doesn't work yet (gets MMC errors)
|
||||
* - latency can reach hundreds of ms, probably because of scheduling delays
|
||||
* - packets go through about three queues before finally hitting the network
|
||||
*/
|
||||
|
||||
/*
|
||||
* Differences from Atheros' HIFs:
|
||||
*
|
||||
* - synchronous and asynchronous requests may get reordered with respect to
|
||||
* each other, e.g., if HIFReadWrite returns for an asynchronous request and
|
||||
* then HIFReadWrite is called for a synchronous request, the synchronous
|
||||
* request may be executed before the asynchronous request.
|
||||
*
|
||||
* - request queue locking seems unnecessarily complex in the Atheros HIFs.
|
||||
*
|
||||
* - Atheros mask interrupts by calling sdio_claim_irq/sdio_release_irq, which
|
||||
* can cause quite a bit of overhead. This HIF has its own light-weight
|
||||
* interrupt masking.
|
||||
*
|
||||
* - Atheros call deviceInsertedHandler from a thread spawned off the probe or
|
||||
* device insertion function. The original explanation for the Atheros SDIO
|
||||
* stack said that this is done because a delay is needed to let the chip
|
||||
* complete initialization. There is indeed a one second delay in the thread.
|
||||
*
|
||||
* The Atheros Linux SDIO HIF removes the delay and only retains the thread.
|
||||
* Experimentally removing the thread didn't show any conflicts, so let's get
|
||||
* rid of it for good.
|
||||
*
|
||||
* - The Atheros SDIO stack with Samuel's driver sets SDIO_CCCR_POWER in
|
||||
* SDIO_POWER_EMPC. Atheros' Linux SDIO code apparently doesn't. We don't
|
||||
* either, and this seems to work fine.
|
||||
* @@@ Need to check this with Atheros.
|
||||
*/
|
||||
|
||||
|
||||
#define MBOXES 4
|
||||
|
||||
#define HIF_MBOX_BLOCK_SIZE 128
|
||||
#define HIF_MBOX_BASE_ADDR 0x800
|
||||
#define HIF_MBOX_WIDTH 0x800
|
||||
#define HIF_MBOX_START_ADDR(mbox) \
|
||||
(HIF_MBOX_BASE_ADDR+(mbox)*HIF_MBOX_WIDTH)
|
||||
|
||||
|
||||
struct hif_device {
|
||||
void *htc_handle;
|
||||
struct sdio_func *func;
|
||||
|
||||
/*
|
||||
* @@@ our sweet little bit of bogosity - the mechanism that lets us
|
||||
* use the SDIO stack from softirqs. This really wants to use skbs.
|
||||
*/
|
||||
struct list_head queue;
|
||||
spinlock_t queue_lock;
|
||||
struct task_struct *io_task;
|
||||
wait_queue_head_t wait;
|
||||
|
||||
/*
|
||||
* activate_lock protects "active" and the activation/deactivation
|
||||
* process itself.
|
||||
*
|
||||
* Relation to other locks: The SDIO function can be claimed while
|
||||
* activate_lock is being held, but trying to acquire activate_lock
|
||||
* while having ownership of the SDIO function could cause a deadlock.
|
||||
*/
|
||||
int active;
|
||||
struct mutex activate_lock;
|
||||
};
|
||||
|
||||
struct hif_request {
|
||||
struct list_head list;
|
||||
struct sdio_func *func;
|
||||
int (*read)(struct sdio_func *func,
|
||||
void *dst, unsigned int addr, int count);
|
||||
int (*write)(struct sdio_func *func,
|
||||
unsigned int addr, void *src, int count);
|
||||
void *buf;
|
||||
unsigned long addr;
|
||||
int len;
|
||||
A_STATUS (*completion)(void *context, A_STATUS status);
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
static HTC_CALLBACKS htcCallbacks;
|
||||
|
||||
/*
|
||||
* shutdown_lock prevents recursion through HIFShutDownDevice
|
||||
*/
|
||||
static DEFINE_MUTEX(shutdown_lock);
|
||||
|
||||
|
||||
/* ----- Request processing ------------------------------------------------ */
|
||||
|
||||
|
||||
static A_STATUS process_request(struct hif_request *req)
|
||||
{
|
||||
int ret;
|
||||
A_STATUS status;
|
||||
|
||||
dev_dbg(&req->func->dev, "process_request(req %p)\n", req);
|
||||
sdio_claim_host(req->func);
|
||||
if (req->read) {
|
||||
ret = req->read(req->func, req->buf, req->addr, req->len);
|
||||
} else {
|
||||
ret = req->write(req->func, req->addr, req->buf, req->len);
|
||||
}
|
||||
sdio_release_host(req->func);
|
||||
status = ret ? A_ERROR : A_OK;
|
||||
if (req->completion)
|
||||
req->completion(req->context, status);
|
||||
kfree(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void enqueue_request(struct hif_device *hif, struct hif_request *req)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(&req->func->dev, "enqueue_request(req %p)\n", req);
|
||||
spin_lock_irqsave(&hif->queue_lock, flags);
|
||||
list_add_tail(&req->list, &hif->queue);
|
||||
spin_unlock_irqrestore(&hif->queue_lock, flags);
|
||||
wake_up(&hif->wait);
|
||||
}
|
||||
|
||||
|
||||
static struct hif_request *dequeue_request(struct hif_device *hif)
|
||||
{
|
||||
struct hif_request *req;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hif->queue_lock, flags);
|
||||
if (list_empty(&hif->queue))
|
||||
req = NULL;
|
||||
else {
|
||||
req = list_first_entry(&hif->queue,
|
||||
struct hif_request, list);
|
||||
list_del(&req->list);
|
||||
}
|
||||
spin_unlock_irqrestore(&hif->queue_lock, flags);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static void wait_queue_empty(struct hif_device *hif)
|
||||
{
|
||||
unsigned long flags;
|
||||
int empty;
|
||||
|
||||
while (1) {
|
||||
spin_lock_irqsave(&hif->queue_lock, flags);
|
||||
empty = list_empty(&hif->queue);
|
||||
spin_unlock_irqrestore(&hif->queue_lock, flags);
|
||||
if (empty)
|
||||
break;
|
||||
else
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int io(void *data)
|
||||
{
|
||||
struct hif_device *hif = data;
|
||||
struct sched_param param = { .sched_priority = 2 };
|
||||
/* one priority level slower than ksdioirqd (which is at 1) */
|
||||
DEFINE_WAIT(wait);
|
||||
struct hif_request *req;
|
||||
|
||||
sched_setscheduler(current, SCHED_FIFO, ¶m);
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
/*
|
||||
* Since we never use signals here, one might think
|
||||
* that this ought to be TASK_UNINTERRUPTIBLE. However,
|
||||
* such a task would increase the load average and,
|
||||
* worse, it would trigger the softlockup check.
|
||||
*/
|
||||
prepare_to_wait(&hif->wait, &wait, TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop()) {
|
||||
finish_wait(&hif->wait, &wait);
|
||||
return 0;
|
||||
}
|
||||
req = dequeue_request(hif);
|
||||
if (req)
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
finish_wait(&hif->wait, &wait);
|
||||
|
||||
(void) process_request(req);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
A_STATUS HIFReadWrite(HIF_DEVICE *hif, A_UINT32 address, A_UCHAR *buffer,
|
||||
A_UINT32 length, A_UINT32 request, void *context)
|
||||
{
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
struct hif_request *req;
|
||||
|
||||
dev_dbg(dev, "HIFReadWrite(device %p, address 0x%x, buffer %p, "
|
||||
"length %d, request 0x%x, context %p)\n",
|
||||
hif, address, buffer, length, request, context);
|
||||
|
||||
BUG_ON(!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)));
|
||||
BUG_ON(!(request & (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)));
|
||||
BUG_ON(!(request & (HIF_READ | HIF_WRITE)));
|
||||
BUG_ON(!(request & HIF_EXTENDED_IO));
|
||||
|
||||
if (address >= HIF_MBOX_START_ADDR(0) &&
|
||||
address < HIF_MBOX_START_ADDR(MBOXES+1)) {
|
||||
BUG_ON(length > HIF_MBOX_WIDTH);
|
||||
/* Adjust the address so that the last byte falls on the EOM
|
||||
address. */
|
||||
address += HIF_MBOX_WIDTH-length;
|
||||
}
|
||||
|
||||
req = kzalloc(sizeof(*req), GFP_ATOMIC);
|
||||
if (!req) {
|
||||
if (request & HIF_ASYNCHRONOUS)
|
||||
htcCallbacks.rwCompletionHandler(context, A_ERROR);
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
req->func = hif->func;
|
||||
req->addr = address;
|
||||
req->buf = buffer;
|
||||
req->len = length;
|
||||
|
||||
if (request & HIF_READ) {
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
req->read = sdio_readsb;
|
||||
else
|
||||
req->read = sdio_memcpy_fromio;
|
||||
} else {
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
req->write = sdio_writesb;
|
||||
else
|
||||
req->write = sdio_memcpy_toio;
|
||||
}
|
||||
|
||||
if (!(request & HIF_ASYNCHRONOUS))
|
||||
return process_request(req);
|
||||
|
||||
req->completion = htcCallbacks.rwCompletionHandler;
|
||||
req->context = context;
|
||||
enqueue_request(hif, req);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Interrupt handling ------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* Volatile ought to be good enough to make gcc do the right thing on S3C24xx.
|
||||
* No need to use atomic or put barriers, keeping the code more readable.
|
||||
*
|
||||
* Warning: this story changes if going SMP/SMT.
|
||||
*/
|
||||
|
||||
static volatile int masked = 1;
|
||||
static volatile int pending;
|
||||
static volatile int in_interrupt;
|
||||
|
||||
|
||||
static void ar6000_do_irq(struct sdio_func *func)
|
||||
{
|
||||
HIF_DEVICE *hif = sdio_get_drvdata(func);
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
A_STATUS status;
|
||||
|
||||
dev_dbg(dev, "ar6000_do_irq -> %p\n", htcCallbacks.dsrHandler);
|
||||
|
||||
status = htcCallbacks.dsrHandler(hif->htc_handle);
|
||||
BUG_ON(status != A_OK);
|
||||
}
|
||||
|
||||
|
||||
static void sdio_ar6000_irq(struct sdio_func *func)
|
||||
{
|
||||
HIF_DEVICE *hif = sdio_get_drvdata(func);
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
|
||||
dev_dbg(dev, "sdio_ar6000_irq\n");
|
||||
|
||||
in_interrupt = 1;
|
||||
if (masked) {
|
||||
in_interrupt = 0;
|
||||
pending++;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* @@@ This is ugly. If we don't drop the lock, we'll deadlock when
|
||||
* the handler tries to do SDIO. So there are four choices:
|
||||
*
|
||||
* 1) Break the call chain by calling the callback from a workqueue.
|
||||
* Ugh.
|
||||
* 2) Make process_request aware that we already have the lock.
|
||||
* 3) Drop the lock. Which is ugly but should be safe as long as we're
|
||||
* making sure the device doesn't go away.
|
||||
* 4) Change the AR6k driver such that it only issues asynchronous
|
||||
* quests when called from an interrupt.
|
||||
*
|
||||
* Solution 2) is probably the best for now. Will try it later.
|
||||
*/
|
||||
sdio_release_host(func);
|
||||
ar6000_do_irq(func);
|
||||
sdio_claim_host(func);
|
||||
in_interrupt = 0;
|
||||
}
|
||||
|
||||
|
||||
void HIFAckInterrupt(HIF_DEVICE *hif)
|
||||
{
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
|
||||
dev_dbg(dev, "HIFAckInterrupt\n");
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
void HIFUnMaskInterrupt(HIF_DEVICE *hif)
|
||||
{
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
|
||||
dev_dbg(dev, "HIFUnMaskInterrupt\n");
|
||||
do {
|
||||
masked = 1;
|
||||
if (pending) {
|
||||
pending = 0;
|
||||
ar6000_do_irq(hif->func);
|
||||
/* We may take an interrupt before unmasking and thus
|
||||
get it pending. In this case, we just loop back. */
|
||||
}
|
||||
masked = 0;
|
||||
}
|
||||
while (pending);
|
||||
}
|
||||
|
||||
|
||||
void HIFMaskInterrupt(HIF_DEVICE *hif)
|
||||
{
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
|
||||
dev_dbg(dev, "HIFMaskInterrupt\n");
|
||||
/*
|
||||
* Since sdio_ar6000_irq can also be called from a process context, we
|
||||
* may conceivably end up racing with it. Thus, we need to wait until
|
||||
* we can be sure that no concurrent interrupt processing is going on
|
||||
* before we return.
|
||||
*
|
||||
* Note: this may be a bit on the paranoid side - the callers may
|
||||
* actually be nice enough to disable scheduling. Check later.
|
||||
*/
|
||||
masked = 1;
|
||||
while (in_interrupt)
|
||||
yield();
|
||||
}
|
||||
|
||||
|
||||
/* ----- HIF API glue functions -------------------------------------------- */
|
||||
|
||||
|
||||
struct device *HIFGetOSDevice(HIF_DEVICE *hif)
|
||||
{
|
||||
return &hif->func->dev;
|
||||
}
|
||||
|
||||
|
||||
void HIFSetHandle(void *hif_handle, void *handle)
|
||||
{
|
||||
HIF_DEVICE *hif = (HIF_DEVICE *) hif_handle;
|
||||
|
||||
hif->htc_handle = handle;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Device configuration (HIF side) ----------------------------------- */
|
||||
|
||||
|
||||
A_STATUS HIFConfigureDevice(HIF_DEVICE *hif,
|
||||
HIF_DEVICE_CONFIG_OPCODE opcode, void *config, A_UINT32 configLen)
|
||||
{
|
||||
struct device *dev = HIFGetOSDevice(hif);
|
||||
HIF_DEVICE_IRQ_PROCESSING_MODE *ipm_cfg = config;
|
||||
A_UINT32 *mbs_cfg = config;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "HIFConfigureDevice\n");
|
||||
|
||||
switch (opcode) {
|
||||
case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
|
||||
for (i = 0; i != MBOXES; i++)
|
||||
mbs_cfg[i] = HIF_MBOX_BLOCK_SIZE;
|
||||
break;
|
||||
case HIF_DEVICE_GET_MBOX_ADDR:
|
||||
for (i = 0; i != MBOXES; i++)
|
||||
mbs_cfg[i] = HIF_MBOX_START_ADDR(i);
|
||||
break;
|
||||
case HIF_DEVICE_GET_IRQ_PROC_MODE:
|
||||
*ipm_cfg = HIF_DEVICE_IRQ_SYNC_ONLY;
|
||||
// *ipm_cfg = HIF_DEVICE_IRQ_ASYNC_SYNC;
|
||||
break;
|
||||
default:
|
||||
return A_ERROR;
|
||||
}
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Device probe and removal (Linux side) ----------------------------- */
|
||||
|
||||
|
||||
static int ar6000_do_activate(struct hif_device *hif)
|
||||
{
|
||||
struct sdio_func *func = hif->func;
|
||||
struct device *dev = &func->dev;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "ar6000_do_activate\n");
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_enable_func(func);
|
||||
|
||||
INIT_LIST_HEAD(&hif->queue);
|
||||
init_waitqueue_head(&hif->wait);
|
||||
spin_lock_init(&hif->queue_lock);
|
||||
|
||||
ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "sdio_set_block_size returns %d\n", ret);
|
||||
goto out_enabled;
|
||||
}
|
||||
ret = sdio_claim_irq(func, sdio_ar6000_irq);
|
||||
if (ret) {
|
||||
dev_err(dev, "sdio_claim_irq returns %d\n", ret);
|
||||
goto out_enabled;
|
||||
}
|
||||
/* Set SDIO_BUS_CD_DISABLE in SDIO_CCCR_IF ? */
|
||||
#if 0
|
||||
sdio_f0_writeb(func, SDIO_CCCR_CAP_E4MI, SDIO_CCCR_CAPS, &ret);
|
||||
if (ret) {
|
||||
dev_err(dev, "sdio_f0_writeb(SDIO_CCCR_CAPS) returns %d\n",
|
||||
ret);
|
||||
goto out_got_irq;
|
||||
}
|
||||
#else
|
||||
if (0) /* avoid warning */
|
||||
goto out_got_irq;
|
||||
#endif
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
hif->io_task = kthread_run(io, hif, "ar6000_io");
|
||||
ret = IS_ERR(hif->io_task);
|
||||
if (ret) {
|
||||
dev_err(dev, "kthread_run(ar6000_io): %d\n", ret);
|
||||
goto out_func_ready;
|
||||
}
|
||||
|
||||
ret = htcCallbacks.deviceInsertedHandler(hif);
|
||||
if (ret == A_OK)
|
||||
return 0;
|
||||
|
||||
dev_err(dev, "deviceInsertedHandler: %d\n", ret);
|
||||
|
||||
ret = kthread_stop(hif->io_task);
|
||||
if (ret)
|
||||
dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
|
||||
|
||||
out_func_ready:
|
||||
sdio_claim_host(func);
|
||||
|
||||
out_got_irq:
|
||||
sdio_release_irq(func);
|
||||
|
||||
out_enabled:
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void ar6000_do_deactivate(struct hif_device *hif)
|
||||
{
|
||||
struct sdio_func *func = hif->func;
|
||||
struct device *dev = &func->dev;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "ar6000_do_deactivate\n");
|
||||
if (!hif->active)
|
||||
return;
|
||||
|
||||
if (mutex_trylock(&shutdown_lock)) {
|
||||
/*
|
||||
* Funny, Atheros' HIF does this call, but this just puts us in
|
||||
* a recursion through HTCShutDown/HIFShutDown if unloading the
|
||||
* module.
|
||||
*
|
||||
* However, we need it for suspend/resume. See the comment at
|
||||
* HIFShutDown, below.
|
||||
*/
|
||||
ret = htcCallbacks.deviceRemovedHandler(hif->htc_handle, A_OK);
|
||||
if (ret != A_OK)
|
||||
dev_err(dev, "deviceRemovedHandler: %d\n", ret);
|
||||
mutex_unlock(&shutdown_lock);
|
||||
}
|
||||
wait_queue_empty(hif);
|
||||
ret = kthread_stop(hif->io_task);
|
||||
if (ret)
|
||||
dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
|
||||
sdio_claim_host(func);
|
||||
sdio_release_irq(func);
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
}
|
||||
|
||||
|
||||
static int ar6000_activate(struct hif_device *hif)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&hif->func->dev, "ar6000_activate\n");
|
||||
mutex_lock(&hif->activate_lock);
|
||||
if (!hif->active) {
|
||||
ret = ar6000_do_activate(hif);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: Failed to activate %d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
hif->active = 1;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&hif->activate_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void ar6000_deactivate(struct hif_device *hif)
|
||||
{
|
||||
dev_dbg(&hif->func->dev, "ar6000_deactivate\n");
|
||||
mutex_lock(&hif->activate_lock);
|
||||
if (hif->active) {
|
||||
ar6000_do_deactivate(hif);
|
||||
hif->active = 0;
|
||||
}
|
||||
mutex_unlock(&hif->activate_lock);
|
||||
}
|
||||
|
||||
|
||||
static int ar6000_rfkill_cb(void *data, int on)
|
||||
{
|
||||
struct hif_device *hif = data;
|
||||
struct sdio_func *func = hif->func;
|
||||
struct device *dev = &func->dev;
|
||||
|
||||
dev_dbg(dev, "ar6000_rfkill_cb: on %d\n", on);
|
||||
if (on)
|
||||
return ar6000_activate(hif);
|
||||
ar6000_deactivate(hif);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int sdio_ar6000_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct device *dev = &func->dev;
|
||||
struct hif_device *hif;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(dev, "sdio_ar6000_probe\n");
|
||||
BUG_ON(!htcCallbacks.deviceInsertedHandler);
|
||||
|
||||
hif = kzalloc(sizeof(*hif), GFP_KERNEL);
|
||||
if (!hif)
|
||||
return -ENOMEM;
|
||||
|
||||
sdio_set_drvdata(func, hif);
|
||||
hif->func = func;
|
||||
mutex_init(&hif->activate_lock);
|
||||
hif->active = 0;
|
||||
|
||||
if (gta02_wlan_query_rfkill_lock())
|
||||
ret = ar6000_activate(hif);
|
||||
if (!ret) {
|
||||
gta02_wlan_set_rfkill_cb(ar6000_rfkill_cb, hif);
|
||||
return 0;
|
||||
}
|
||||
gta02_wlan_query_rfkill_unlock();
|
||||
sdio_set_drvdata(func, NULL);
|
||||
kfree(hif);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void sdio_ar6000_remove(struct sdio_func *func)
|
||||
{
|
||||
struct device *dev = &func->dev;
|
||||
HIF_DEVICE *hif = sdio_get_drvdata(func);
|
||||
|
||||
dev_dbg(dev, "sdio_ar6000_remove\n");
|
||||
gta02_wlan_clear_rfkill_cb();
|
||||
ar6000_deactivate(hif);
|
||||
sdio_set_drvdata(func, NULL);
|
||||
kfree(hif);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Device registration/unregistration (called by HIF) ---------------- */
|
||||
|
||||
|
||||
#define ATHEROS_SDIO_DEVICE(id, offset) \
|
||||
SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_##id | (offset))
|
||||
|
||||
static const struct sdio_device_id sdio_ar6000_ids[] = {
|
||||
{ ATHEROS_SDIO_DEVICE(AR6002, 0) },
|
||||
{ ATHEROS_SDIO_DEVICE(AR6002, 0x1) },
|
||||
{ ATHEROS_SDIO_DEVICE(AR6001, 0x8) },
|
||||
{ ATHEROS_SDIO_DEVICE(AR6001, 0x9) },
|
||||
{ ATHEROS_SDIO_DEVICE(AR6001, 0xa) },
|
||||
{ ATHEROS_SDIO_DEVICE(AR6001, 0xb) },
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, sdio_ar6000_ids);
|
||||
|
||||
|
||||
static struct sdio_driver sdio_ar6000_driver = {
|
||||
.probe = sdio_ar6000_probe,
|
||||
.remove = sdio_ar6000_remove,
|
||||
.name = "sdio_ar6000",
|
||||
.id_table = sdio_ar6000_ids,
|
||||
};
|
||||
|
||||
|
||||
int HIFInit(HTC_CALLBACKS *callbacks)
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!callbacks);
|
||||
|
||||
printk(KERN_DEBUG "HIFInit\n");
|
||||
htcCallbacks = *callbacks;
|
||||
|
||||
ret = sdio_register_driver(&sdio_ar6000_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR
|
||||
"sdio_register_driver(sdio_ar6000_driver): %d\n", ret);
|
||||
return A_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We have four possible call chains here:
|
||||
*
|
||||
* System shutdown/reboot:
|
||||
*
|
||||
* kernel_restart_prepare ...> device_shutdown ... > s3cmci_shutdown ->
|
||||
* mmc_remove_host ..> sdio_bus_remove -> sdio_ar6000_remove ->
|
||||
* ar6000_deactivate -> ar6000_do_deactivate ->
|
||||
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
|
||||
*
|
||||
* This is roughly the same sequence as suspend, described below.
|
||||
*
|
||||
* Module removal:
|
||||
*
|
||||
* sys_delete_module -> ar6000_cleanup_module -> HTCShutDown ->
|
||||
* HIFShutDownDevice -> sdio_unregister_driver ...> sdio_bus_remove ->
|
||||
* sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate
|
||||
*
|
||||
* In this case, HIFShutDownDevice must call sdio_unregister_driver to
|
||||
* notify the driver about its removal. ar6000_do_deactivate must not call
|
||||
* deviceRemovedHandler, because that would loop back into HIFShutDownDevice.
|
||||
*
|
||||
* Suspend:
|
||||
*
|
||||
* device_suspend ...> s3cmci_suspend ...> sdio_bus_remove ->
|
||||
* sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate ->
|
||||
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
|
||||
*
|
||||
* We must call deviceRemovedHandler to inform the ar6k stack that the device
|
||||
* has been removed. Since HTCTargetRemovedHandler calls back into
|
||||
* HIFShutDownDevice, we must also prevent the call to
|
||||
* sdio_unregister_driver, or we'd end up recursing into the SDIO stack,
|
||||
* eventually deadlocking somewhere.
|
||||
*
|
||||
* rfkill:
|
||||
*
|
||||
* rfkill_state_store -> rfkill_toggle_radio -> gta02_wlan_toggle_radio ->
|
||||
* ar6000_rfkill_cb -> ar6000_deactivate -> ar6000_do_deactivate ->
|
||||
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
|
||||
*
|
||||
* This is similar to suspend - only the entry point changes.
|
||||
*/
|
||||
|
||||
void HIFShutDownDevice(HIF_DEVICE *hif)
|
||||
{
|
||||
/* Beware, HTCShutDown calls us with hif == NULL ! */
|
||||
if (mutex_trylock(&shutdown_lock)) {
|
||||
sdio_unregister_driver(&sdio_ar6000_driver);
|
||||
mutex_unlock(&shutdown_lock);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* @file: hif_internal.h
|
||||
*
|
||||
* @abstract: internal header file for hif layer
|
||||
*
|
||||
* @notice: Copyright (c) 2004-2006 Atheros Communications 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sdio/ctsystem.h>
|
||||
#include <linux/sdio/sdio_busdriver.h>
|
||||
#include <linux/sdio/_sdio_defs.h>
|
||||
#include <linux/sdio/sdio_lib.h>
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "hif.h"
|
||||
|
||||
#define MANUFACTURER_ID_AR6001_BASE 0x100
|
||||
#define MANUFACTURER_ID_AR6002_BASE 0x200
|
||||
#define FUNCTION_CLASS 0x0
|
||||
#define MANUFACTURER_CODE 0x271
|
||||
|
||||
#define BUS_REQUEST_MAX_NUM 64
|
||||
|
||||
#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000
|
||||
#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20
|
||||
#define FLAGS_CARD_ENAB 0x02
|
||||
#define FLAGS_CARD_IRQ_UNMSK 0x04
|
||||
|
||||
#define HIF_MBOX_BLOCK_SIZE 128
|
||||
#define HIF_MBOX_BASE_ADDR 0x800
|
||||
#define HIF_MBOX_WIDTH 0x800
|
||||
#define HIF_MBOX0_BLOCK_SIZE 1
|
||||
#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
|
||||
#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
|
||||
#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
|
||||
|
||||
#define HIF_MBOX_START_ADDR(mbox) \
|
||||
HIF_MBOX_BASE_ADDR + mbox * HIF_MBOX_WIDTH
|
||||
|
||||
#define HIF_MBOX_END_ADDR(mbox) \
|
||||
HIF_MBOX_START_ADDR(mbox) + HIF_MBOX_WIDTH - 1
|
||||
|
||||
struct hif_device {
|
||||
SDDEVICE *handle;
|
||||
void *htc_handle;
|
||||
OSKERNEL_HELPER insert_helper;
|
||||
BOOL helper_started;
|
||||
};
|
||||
|
||||
typedef struct target_function_context {
|
||||
SDFUNCTION function; /* function description of the bus driver */
|
||||
OS_SEMAPHORE instanceSem; /* instance lock. Unused */
|
||||
SDLIST instanceList; /* list of instances. Unused */
|
||||
} TARGET_FUNCTION_CONTEXT;
|
||||
|
||||
typedef struct bus_request {
|
||||
struct bus_request *next;
|
||||
SDREQUEST *request;
|
||||
void *context;
|
||||
} BUS_REQUEST;
|
||||
|
||||
BOOL
|
||||
hifDeviceInserted(SDFUNCTION *function, SDDEVICE *device);
|
||||
|
||||
void
|
||||
hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *device);
|
||||
|
||||
SDREQUEST *
|
||||
hifAllocateDeviceRequest(SDDEVICE *device);
|
||||
|
||||
void
|
||||
hifFreeDeviceRequest(SDREQUEST *request);
|
||||
|
||||
void
|
||||
hifRWCompletionHandler(SDREQUEST *request);
|
||||
|
||||
void
|
||||
hifIRQHandler(void *context);
|
||||
|
||||
HIF_DEVICE *
|
||||
addHifDevice(SDDEVICE *handle);
|
||||
|
||||
HIF_DEVICE *
|
||||
getHifDevice(SDDEVICE *handle);
|
||||
|
||||
void
|
||||
delHifDevice(SDDEVICE *handle);
|
|
@ -0,0 +1,991 @@
|
|||
/*
|
||||
* AR6K device layer that handles register level I/O
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "AR6Khwreg.h"
|
||||
#include "a_osapi.h"
|
||||
#include "a_debug.h"
|
||||
#include "hif.h"
|
||||
#include "htc_packet.h"
|
||||
#include "ar6k.h"
|
||||
|
||||
#define MAILBOX_FOR_BLOCK_SIZE 1
|
||||
|
||||
extern A_UINT32 resetok;
|
||||
|
||||
static A_STATUS DevEnableInterrupts(AR6K_DEVICE *pDev);
|
||||
static A_STATUS DevDisableInterrupts(AR6K_DEVICE *pDev);
|
||||
|
||||
#define LOCK_AR6K(p) A_MUTEX_LOCK(&(p)->Lock);
|
||||
#define UNLOCK_AR6K(p) A_MUTEX_UNLOCK(&(p)->Lock);
|
||||
|
||||
void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket)
|
||||
{
|
||||
LOCK_AR6K(pDev);
|
||||
HTC_PACKET_ENQUEUE(&pDev->RegisterIOList,pPacket);
|
||||
UNLOCK_AR6K(pDev);
|
||||
}
|
||||
|
||||
HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev)
|
||||
{
|
||||
HTC_PACKET *pPacket;
|
||||
|
||||
LOCK_AR6K(pDev);
|
||||
pPacket = HTC_PACKET_DEQUEUE(&pDev->RegisterIOList);
|
||||
UNLOCK_AR6K(pDev);
|
||||
|
||||
return pPacket;
|
||||
}
|
||||
|
||||
A_STATUS DevSetup(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_UINT32 mailboxaddrs[AR6K_MAILBOXES];
|
||||
A_UINT32 blocksizes[AR6K_MAILBOXES];
|
||||
A_STATUS status = A_OK;
|
||||
int i;
|
||||
|
||||
AR_DEBUG_ASSERT(AR6K_IRQ_PROC_REGS_SIZE == 16);
|
||||
AR_DEBUG_ASSERT(AR6K_IRQ_ENABLE_REGS_SIZE == 4);
|
||||
|
||||
do {
|
||||
/* give a handle to HIF for this target */
|
||||
HIFSetHandle(pDev->HIFDevice, (void *)pDev);
|
||||
/* initialize our free list of IO packets */
|
||||
INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList);
|
||||
A_MUTEX_INIT(&pDev->Lock);
|
||||
|
||||
/* get the addresses for all 4 mailboxes */
|
||||
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
|
||||
mailboxaddrs, sizeof(mailboxaddrs));
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* carve up register I/O packets (these are for ASYNC register I/O ) */
|
||||
for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) {
|
||||
HTC_PACKET *pIOPacket;
|
||||
pIOPacket = &pDev->RegIOBuffers[i].HtcPacket;
|
||||
SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket,
|
||||
pDev,
|
||||
pDev->RegIOBuffers[i].Buffer,
|
||||
AR6K_REG_IO_BUFFER_SIZE,
|
||||
0); /* don't care */
|
||||
AR6KFreeIOPacket(pDev,pIOPacket);
|
||||
}
|
||||
|
||||
/* get the address of the mailbox we are using */
|
||||
pDev->MailboxAddress = mailboxaddrs[HTC_MAILBOX];
|
||||
|
||||
/* get the block sizes */
|
||||
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
|
||||
blocksizes, sizeof(blocksizes));
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* note: we actually get the block size of a mailbox other than 0, for SDIO the block
|
||||
* size on mailbox 0 is artificially set to 1. So we use the block size that is set
|
||||
* for the other 3 mailboxes */
|
||||
pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE];
|
||||
/* must be a power of 2 */
|
||||
AR_DEBUG_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0);
|
||||
|
||||
/* assemble mask, used for padding to a block */
|
||||
pDev->BlockMask = pDev->BlockSize - 1;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n",
|
||||
pDev->BlockSize, pDev->MailboxAddress));
|
||||
|
||||
pDev->GetPendingEventsFunc = NULL;
|
||||
/* see if the HIF layer implements the get pending events function */
|
||||
HIFConfigureDevice(pDev->HIFDevice,
|
||||
HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
|
||||
&pDev->GetPendingEventsFunc,
|
||||
sizeof(pDev->GetPendingEventsFunc));
|
||||
|
||||
/* assume we can process HIF interrupt events asynchronously */
|
||||
pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC;
|
||||
|
||||
/* see if the HIF layer overrides this assumption */
|
||||
HIFConfigureDevice(pDev->HIFDevice,
|
||||
HIF_DEVICE_GET_IRQ_PROC_MODE,
|
||||
&pDev->HifIRQProcessingMode,
|
||||
sizeof(pDev->HifIRQProcessingMode));
|
||||
|
||||
switch (pDev->HifIRQProcessingMode) {
|
||||
case HIF_DEVICE_IRQ_SYNC_ONLY:
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is SYNC ONLY\n"));
|
||||
break;
|
||||
case HIF_DEVICE_IRQ_ASYNC_SYNC:
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n"));
|
||||
break;
|
||||
default:
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
pDev->HifMaskUmaskRecvEvent = NULL;
|
||||
|
||||
/* see if the HIF layer implements the mask/unmask recv events function */
|
||||
HIFConfigureDevice(pDev->HIFDevice,
|
||||
HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
|
||||
&pDev->HifMaskUmaskRecvEvent,
|
||||
sizeof(pDev->HifMaskUmaskRecvEvent));
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%X , 0x%X\n",
|
||||
(A_UINT32)pDev->GetPendingEventsFunc, (A_UINT32)pDev->HifMaskUmaskRecvEvent));
|
||||
|
||||
status = DevDisableInterrupts(pDev);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
/* make sure handle is cleared */
|
||||
HIFSetHandle(pDev->HIFDevice, NULL);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static A_STATUS DevEnableInterrupts(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_STATUS status;
|
||||
AR6K_IRQ_ENABLE_REGISTERS regs;
|
||||
|
||||
LOCK_AR6K(pDev);
|
||||
|
||||
/* Enable all the interrupts except for the dragon interrupt */
|
||||
pDev->IrqEnableRegisters.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) |
|
||||
INT_STATUS_ENABLE_CPU_SET(0x01) |
|
||||
INT_STATUS_ENABLE_COUNTER_SET(0x01);
|
||||
|
||||
if (NULL == pDev->GetPendingEventsFunc) {
|
||||
pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
|
||||
} else {
|
||||
/* The HIF layer provided us with a pending events function which means that
|
||||
* the detection of pending mbox messages is handled in the HIF layer.
|
||||
* This is the case for the SPI2 interface.
|
||||
* In the normal case we enable MBOX interrupts, for the case
|
||||
* with HIFs that offer this mechanism, we keep these interrupts
|
||||
* masked */
|
||||
pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
|
||||
}
|
||||
|
||||
|
||||
/* Set up the CPU Interrupt Status Register */
|
||||
pDev->IrqEnableRegisters.cpu_int_status_enable = CPU_INT_STATUS_ENABLE_BIT_SET(0x00);
|
||||
|
||||
/* Set up the Error Interrupt Status Register */
|
||||
pDev->IrqEnableRegisters.error_status_enable =
|
||||
ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) |
|
||||
ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01);
|
||||
|
||||
/* Set up the Counter Interrupt Status Register (only for debug interrupt to catch fatal errors) */
|
||||
pDev->IrqEnableRegisters.counter_int_status_enable =
|
||||
COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK);
|
||||
|
||||
/* copy into our temp area */
|
||||
A_MEMCPY(®s,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
|
||||
|
||||
UNLOCK_AR6K(pDev);
|
||||
|
||||
/* always synchronous */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_enable,
|
||||
AR6K_IRQ_ENABLE_REGS_SIZE,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
/* Can't write it for some reason */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("Failed to update interrupt control registers err: %d\n", status));
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static A_STATUS DevDisableInterrupts(AR6K_DEVICE *pDev)
|
||||
{
|
||||
AR6K_IRQ_ENABLE_REGISTERS regs;
|
||||
|
||||
LOCK_AR6K(pDev);
|
||||
/* Disable all interrupts */
|
||||
pDev->IrqEnableRegisters.int_status_enable = 0;
|
||||
pDev->IrqEnableRegisters.cpu_int_status_enable = 0;
|
||||
pDev->IrqEnableRegisters.error_status_enable = 0;
|
||||
pDev->IrqEnableRegisters.counter_int_status_enable = 0;
|
||||
/* copy into our temp area */
|
||||
A_MEMCPY(®s,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
|
||||
|
||||
UNLOCK_AR6K(pDev);
|
||||
|
||||
/* always synchronous */
|
||||
return HIFReadWrite(pDev->HIFDevice,
|
||||
INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_enable,
|
||||
AR6K_IRQ_ENABLE_REGS_SIZE,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* enable device interrupts */
|
||||
A_STATUS DevUnmaskInterrupts(AR6K_DEVICE *pDev)
|
||||
{
|
||||
/* Unmask the host controller interrupts */
|
||||
HIFUnMaskInterrupt(pDev->HIFDevice);
|
||||
|
||||
return DevEnableInterrupts(pDev);
|
||||
}
|
||||
|
||||
/* disable all device interrupts */
|
||||
A_STATUS DevMaskInterrupts(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_STATUS status;
|
||||
|
||||
status = DevDisableInterrupts(pDev);
|
||||
|
||||
if (A_SUCCESS(status)) {
|
||||
/* Disable the interrupt at the HIF layer */
|
||||
HIFMaskInterrupt(pDev->HIFDevice);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* callback when our fetch to enable/disable completes */
|
||||
static void DevDoEnableDisableRecvAsyncHandler(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDoEnableDisableRecvAsyncHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
|
||||
|
||||
if (A_FAILED(pPacket->Status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" Failed to disable receiver, status:%d \n", pPacket->Status));
|
||||
}
|
||||
/* free this IO packet */
|
||||
AR6KFreeIOPacket(pDev,pPacket);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDoEnableDisableRecvAsyncHandler \n"));
|
||||
}
|
||||
|
||||
/* disable packet reception (used in case the host runs out of buffers)
|
||||
* this is the "override" method when the HIF reports another methods to
|
||||
* disable recv events */
|
||||
static A_STATUS DevDoEnableDisableRecvOverride(AR6K_DEVICE *pDev, A_BOOL EnableRecv, A_BOOL AsyncMode)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
HTC_PACKET *pIOPacket = NULL;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("DevDoEnableDisableRecvOverride: Enable:%d Mode:%d\n",
|
||||
EnableRecv,AsyncMode));
|
||||
|
||||
do {
|
||||
|
||||
if (AsyncMode) {
|
||||
|
||||
pIOPacket = AR6KAllocIOPacket(pDev);
|
||||
|
||||
if (NULL == pIOPacket) {
|
||||
status = A_NO_MEMORY;
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* stick in our completion routine when the I/O operation completes */
|
||||
pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
|
||||
pIOPacket->pContext = pDev;
|
||||
|
||||
/* call the HIF layer override and do this asynchronously */
|
||||
status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
|
||||
EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
|
||||
pIOPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we get here we are doing it synchronously */
|
||||
status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
|
||||
EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
|
||||
NULL);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status) && (pIOPacket != NULL)) {
|
||||
AR6KFreeIOPacket(pDev,pIOPacket);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* disable packet reception (used in case the host runs out of buffers)
|
||||
* this is the "normal" method using the interrupt enable registers through
|
||||
* the host I/F */
|
||||
static A_STATUS DevDoEnableDisableRecvNormal(AR6K_DEVICE *pDev, A_BOOL EnableRecv, A_BOOL AsyncMode)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
HTC_PACKET *pIOPacket = NULL;
|
||||
AR6K_IRQ_ENABLE_REGISTERS regs;
|
||||
|
||||
/* take the lock to protect interrupt enable shadows */
|
||||
LOCK_AR6K(pDev);
|
||||
|
||||
if (EnableRecv) {
|
||||
pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
|
||||
} else {
|
||||
pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
|
||||
}
|
||||
|
||||
/* copy into our temp area */
|
||||
A_MEMCPY(®s,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
|
||||
UNLOCK_AR6K(pDev);
|
||||
|
||||
do {
|
||||
|
||||
if (AsyncMode) {
|
||||
|
||||
pIOPacket = AR6KAllocIOPacket(pDev);
|
||||
|
||||
if (NULL == pIOPacket) {
|
||||
status = A_NO_MEMORY;
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy values to write to our async I/O buffer */
|
||||
A_MEMCPY(pIOPacket->pBuffer,®s,AR6K_IRQ_ENABLE_REGS_SIZE);
|
||||
|
||||
/* stick in our completion routine when the I/O operation completes */
|
||||
pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
|
||||
pIOPacket->pContext = pDev;
|
||||
|
||||
/* write it out asynchronously */
|
||||
HIFReadWrite(pDev->HIFDevice,
|
||||
INT_STATUS_ENABLE_ADDRESS,
|
||||
pIOPacket->pBuffer,
|
||||
AR6K_IRQ_ENABLE_REGS_SIZE,
|
||||
HIF_WR_ASYNC_BYTE_INC,
|
||||
pIOPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we get here we are doing it synchronously */
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_enable,
|
||||
AR6K_IRQ_ENABLE_REGS_SIZE,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status) && (pIOPacket != NULL)) {
|
||||
AR6KFreeIOPacket(pDev,pIOPacket);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
A_STATUS DevStopRecv(AR6K_DEVICE *pDev, A_BOOL AsyncMode)
|
||||
{
|
||||
if (NULL == pDev->HifMaskUmaskRecvEvent) {
|
||||
return DevDoEnableDisableRecvNormal(pDev,FALSE,AsyncMode);
|
||||
} else {
|
||||
return DevDoEnableDisableRecvOverride(pDev,FALSE,AsyncMode);
|
||||
}
|
||||
}
|
||||
|
||||
A_STATUS DevEnableRecv(AR6K_DEVICE *pDev, A_BOOL AsyncMode)
|
||||
{
|
||||
if (NULL == pDev->HifMaskUmaskRecvEvent) {
|
||||
return DevDoEnableDisableRecvNormal(pDev,TRUE,AsyncMode);
|
||||
} else {
|
||||
return DevDoEnableDisableRecvOverride(pDev,TRUE,AsyncMode);
|
||||
}
|
||||
}
|
||||
|
||||
void DevDumpRegisters(AR6K_IRQ_PROC_REGISTERS *pIrqProcRegs,
|
||||
AR6K_IRQ_ENABLE_REGISTERS *pIrqEnableRegs)
|
||||
{
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("\n<------- Register Table -------->\n"));
|
||||
|
||||
if (pIrqProcRegs != NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Int Status: 0x%x\n",pIrqProcRegs->host_int_status));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("CPU Int Status: 0x%x\n",pIrqProcRegs->cpu_int_status));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Error Int Status: 0x%x\n",pIrqProcRegs->error_int_status));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Counter Int Status: 0x%x\n",pIrqProcRegs->counter_int_status));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Mbox Frame: 0x%x\n",pIrqProcRegs->mbox_frame));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Rx Lookahead Valid: 0x%x\n",pIrqProcRegs->rx_lookahead_valid));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Rx Lookahead 0: 0x%x\n",pIrqProcRegs->rx_lookahead[0]));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Rx Lookahead 1: 0x%x\n",pIrqProcRegs->rx_lookahead[1]));
|
||||
}
|
||||
|
||||
if (pIrqEnableRegs != NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Int Status Enable: 0x%x\n",pIrqEnableRegs->int_status_enable));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
|
||||
("Counter Int Status Enable: 0x%x\n",pIrqEnableRegs->counter_int_status_enable));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("<------------------------------->\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef MBOXHW_UNIT_TEST
|
||||
|
||||
|
||||
/* This is a mailbox hardware unit test that must be called in a schedulable context
|
||||
* This test is very simple, it will send a list of buffers with a counting pattern
|
||||
* and the target will invert the data and send the message back
|
||||
*
|
||||
* the unit test has the following constraints:
|
||||
*
|
||||
* The target has at least 8 buffers of 256 bytes each. The host will send
|
||||
* the following pattern of buffers in rapid succession :
|
||||
*
|
||||
* 1 buffer - 128 bytes
|
||||
* 1 buffer - 256 bytes
|
||||
* 1 buffer - 512 bytes
|
||||
* 1 buffer - 1024 bytes
|
||||
*
|
||||
* The host will send the buffers to one mailbox and wait for buffers to be reflected
|
||||
* back from the same mailbox. The target sends the buffers FIFO order.
|
||||
* Once the final buffer has been received for a mailbox, the next mailbox is tested.
|
||||
*
|
||||
*
|
||||
* Note: To simplifythe test , we assume that the chosen buffer sizes
|
||||
* will fall on a nice block pad
|
||||
*
|
||||
* It is expected that higher-order tests will be written to stress the mailboxes using
|
||||
* a message-based protocol (with some performance timming) that can create more
|
||||
* randomness in the packets sent over mailboxes.
|
||||
*
|
||||
* */
|
||||
|
||||
#define A_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1))
|
||||
|
||||
#define BUFFER_BLOCK_PAD 128
|
||||
|
||||
#if 0
|
||||
#define BUFFER1 128
|
||||
#define BUFFER2 256
|
||||
#define BUFFER3 512
|
||||
#define BUFFER4 1024
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define BUFFER1 80
|
||||
#define BUFFER2 200
|
||||
#define BUFFER3 444
|
||||
#define BUFFER4 800
|
||||
#endif
|
||||
|
||||
#define TOTAL_BYTES (A_ROUND_UP_PWR2(BUFFER1,BUFFER_BLOCK_PAD) + \
|
||||
A_ROUND_UP_PWR2(BUFFER2,BUFFER_BLOCK_PAD) + \
|
||||
A_ROUND_UP_PWR2(BUFFER3,BUFFER_BLOCK_PAD) + \
|
||||
A_ROUND_UP_PWR2(BUFFER4,BUFFER_BLOCK_PAD) )
|
||||
|
||||
#define TEST_BYTES (BUFFER1 + BUFFER2 + BUFFER3 + BUFFER4)
|
||||
|
||||
#define TEST_CREDITS_RECV_TIMEOUT 100
|
||||
|
||||
static A_UINT8 g_Buffer[TOTAL_BYTES];
|
||||
static A_UINT32 g_MailboxAddrs[AR6K_MAILBOXES];
|
||||
static A_UINT32 g_BlockSizes[AR6K_MAILBOXES];
|
||||
|
||||
#define BUFFER_PROC_LIST_DEPTH 4
|
||||
|
||||
typedef struct _BUFFER_PROC_LIST{
|
||||
A_UINT8 *pBuffer;
|
||||
A_UINT32 length;
|
||||
}BUFFER_PROC_LIST;
|
||||
|
||||
|
||||
#define PUSH_BUFF_PROC_ENTRY(pList,len,pCurrpos) \
|
||||
{ \
|
||||
(pList)->pBuffer = (pCurrpos); \
|
||||
(pList)->length = (len); \
|
||||
(pCurrpos) += (len); \
|
||||
(pList)++; \
|
||||
}
|
||||
|
||||
/* a simple and crude way to send different "message" sizes */
|
||||
static void AssembleBufferList(BUFFER_PROC_LIST *pList)
|
||||
{
|
||||
A_UINT8 *pBuffer = g_Buffer;
|
||||
|
||||
#if BUFFER_PROC_LIST_DEPTH < 4
|
||||
#error "Buffer processing list depth is not deep enough!!"
|
||||
#endif
|
||||
|
||||
PUSH_BUFF_PROC_ENTRY(pList,BUFFER1,pBuffer);
|
||||
PUSH_BUFF_PROC_ENTRY(pList,BUFFER2,pBuffer);
|
||||
PUSH_BUFF_PROC_ENTRY(pList,BUFFER3,pBuffer);
|
||||
PUSH_BUFF_PROC_ENTRY(pList,BUFFER4,pBuffer);
|
||||
|
||||
}
|
||||
|
||||
#define FILL_ZERO TRUE
|
||||
#define FILL_COUNTING FALSE
|
||||
static void InitBuffers(A_BOOL Zero)
|
||||
{
|
||||
A_UINT16 *pBuffer16 = (A_UINT16 *)g_Buffer;
|
||||
int i;
|
||||
|
||||
/* fill buffer with 16 bit counting pattern or zeros */
|
||||
for (i = 0; i < (TOTAL_BYTES / 2) ; i++) {
|
||||
if (!Zero) {
|
||||
pBuffer16[i] = (A_UINT16)i;
|
||||
} else {
|
||||
pBuffer16[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static A_BOOL CheckOneBuffer(A_UINT16 *pBuffer16, int Length)
|
||||
{
|
||||
int i;
|
||||
A_UINT16 startCount;
|
||||
A_BOOL success = TRUE;
|
||||
|
||||
/* get the starting count */
|
||||
startCount = pBuffer16[0];
|
||||
/* invert it, this is the expected value */
|
||||
startCount = ~startCount;
|
||||
/* scan the buffer and verify */
|
||||
for (i = 0; i < (Length / 2) ; i++,startCount++) {
|
||||
/* target will invert all the data */
|
||||
if ((A_UINT16)pBuffer16[i] != (A_UINT16)~startCount) {
|
||||
success = FALSE;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid Data Got:0x%X, Expecting:0x%X (offset:%d, total:%d) \n",
|
||||
pBuffer16[i], ((A_UINT16)~startCount), i, Length));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("0x%X 0x%X 0x%X 0x%X \n",
|
||||
pBuffer16[i], pBuffer16[i + 1], pBuffer16[i + 2],pBuffer16[i+3]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static A_BOOL CheckBuffers(void)
|
||||
{
|
||||
int i;
|
||||
A_BOOL success = TRUE;
|
||||
BUFFER_PROC_LIST checkList[BUFFER_PROC_LIST_DEPTH];
|
||||
|
||||
/* assemble the list */
|
||||
AssembleBufferList(checkList);
|
||||
|
||||
/* scan the buffers and verify */
|
||||
for (i = 0; i < BUFFER_PROC_LIST_DEPTH ; i++) {
|
||||
success = CheckOneBuffer((A_UINT16 *)checkList[i].pBuffer, checkList[i].length);
|
||||
if (!success) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer : 0x%X, Length:%d failed verify \n",
|
||||
(A_UINT32)checkList[i].pBuffer, checkList[i].length));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/* find the end marker for the last buffer we will be sending */
|
||||
static A_UINT16 GetEndMarker(void)
|
||||
{
|
||||
A_UINT8 *pBuffer;
|
||||
BUFFER_PROC_LIST checkList[BUFFER_PROC_LIST_DEPTH];
|
||||
|
||||
/* fill up buffers with the normal counting pattern */
|
||||
InitBuffers(FILL_COUNTING);
|
||||
|
||||
/* assemble the list we will be sending down */
|
||||
AssembleBufferList(checkList);
|
||||
/* point to the last 2 bytes of the last buffer */
|
||||
pBuffer = &(checkList[BUFFER_PROC_LIST_DEPTH - 1].pBuffer[(checkList[BUFFER_PROC_LIST_DEPTH - 1].length) - 2]);
|
||||
|
||||
/* the last count in the last buffer is the marker */
|
||||
return (A_UINT16)pBuffer[0] | ((A_UINT16)pBuffer[1] << 8);
|
||||
}
|
||||
|
||||
#define ATH_PRINT_OUT_ZONE ATH_DEBUG_ERR
|
||||
|
||||
/* send the ordered buffers to the target */
|
||||
static A_STATUS SendBuffers(AR6K_DEVICE *pDev, int mbox)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
A_UINT32 request = HIF_WR_SYNC_BLOCK_INC;
|
||||
BUFFER_PROC_LIST sendList[BUFFER_PROC_LIST_DEPTH];
|
||||
int i;
|
||||
int totalBytes = 0;
|
||||
int paddedLength;
|
||||
int totalwPadding = 0;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sending buffers on mailbox : %d \n",mbox));
|
||||
|
||||
/* fill buffer with counting pattern */
|
||||
InitBuffers(FILL_COUNTING);
|
||||
|
||||
/* assemble the order in which we send */
|
||||
AssembleBufferList(sendList);
|
||||
|
||||
for (i = 0; i < BUFFER_PROC_LIST_DEPTH; i++) {
|
||||
|
||||
/* we are doing block transfers, so we need to pad everything to a block size */
|
||||
paddedLength = (sendList[i].length + (g_BlockSizes[mbox] - 1)) &
|
||||
(~(g_BlockSizes[mbox] - 1));
|
||||
|
||||
/* send each buffer synchronously */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
g_MailboxAddrs[mbox],
|
||||
sendList[i].pBuffer,
|
||||
paddedLength,
|
||||
request,
|
||||
NULL);
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
totalBytes += sendList[i].length;
|
||||
totalwPadding += paddedLength;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sent %d bytes (%d padded bytes) to mailbox : %d \n",totalBytes,totalwPadding,mbox));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* poll the mailbox credit counter until we get a credit or timeout */
|
||||
static A_STATUS GetCredits(AR6K_DEVICE *pDev, int mbox, int *pCredits)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
int timeout = TEST_CREDITS_RECV_TIMEOUT;
|
||||
A_UINT8 credits = 0;
|
||||
A_UINT32 address;
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
/* Read the counter register to get credits, this auto-decrements */
|
||||
address = COUNT_DEC_ADDRESS + (AR6K_MAILBOXES + mbox) * 4;
|
||||
status = HIFReadWrite(pDev->HIFDevice, address, &credits, sizeof(credits),
|
||||
HIF_RD_SYNC_BYTE_FIX, NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("Unable to decrement the command credit count register (mbox=%d)\n",mbox));
|
||||
status = A_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (credits) {
|
||||
break;
|
||||
}
|
||||
|
||||
timeout--;
|
||||
|
||||
if (timeout <= 0) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" Timeout reading credit registers (mbox=%d, address:0x%X) \n",mbox,address));
|
||||
status = A_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* delay a little, target may not be ready */
|
||||
msleep(1000);
|
||||
|
||||
}
|
||||
|
||||
if (status == A_OK) {
|
||||
*pCredits = credits;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* wait for the buffers to come back */
|
||||
static A_STATUS RecvBuffers(AR6K_DEVICE *pDev, int mbox)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
A_UINT32 request = HIF_RD_SYNC_BLOCK_INC;
|
||||
BUFFER_PROC_LIST recvList[BUFFER_PROC_LIST_DEPTH];
|
||||
int curBuffer;
|
||||
int credits;
|
||||
int i;
|
||||
int totalBytes = 0;
|
||||
int paddedLength;
|
||||
int totalwPadding = 0;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for buffers on mailbox : %d \n",mbox));
|
||||
|
||||
/* zero the buffers */
|
||||
InitBuffers(FILL_ZERO);
|
||||
|
||||
/* assemble the order in which we should receive */
|
||||
AssembleBufferList(recvList);
|
||||
|
||||
curBuffer = 0;
|
||||
|
||||
while (curBuffer < BUFFER_PROC_LIST_DEPTH) {
|
||||
|
||||
/* get number of buffers that have been completed, this blocks
|
||||
* until we get at least 1 credit or it times out */
|
||||
status = GetCredits(pDev, mbox, &credits);
|
||||
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got %d messages on mailbox : %d \n",credits, mbox));
|
||||
|
||||
/* get all the buffers that are sitting on the queue */
|
||||
for (i = 0; i < credits; i++) {
|
||||
AR_DEBUG_ASSERT(curBuffer < BUFFER_PROC_LIST_DEPTH);
|
||||
/* recv the current buffer synchronously, the buffers should come back in
|
||||
* order... with padding applied by the target */
|
||||
paddedLength = (recvList[curBuffer].length + (g_BlockSizes[mbox] - 1)) &
|
||||
(~(g_BlockSizes[mbox] - 1));
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
g_MailboxAddrs[mbox],
|
||||
recvList[curBuffer].pBuffer,
|
||||
paddedLength,
|
||||
request,
|
||||
NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to read %d bytes on mailbox:%d : address:0x%X \n",
|
||||
recvList[curBuffer].length, mbox, g_MailboxAddrs[mbox]));
|
||||
break;
|
||||
}
|
||||
|
||||
totalwPadding += paddedLength;
|
||||
totalBytes += recvList[curBuffer].length;
|
||||
curBuffer++;
|
||||
}
|
||||
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
/* go back and get some more */
|
||||
credits = 0;
|
||||
}
|
||||
|
||||
if (totalBytes != TEST_BYTES) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got all buffers on mbox:%d total recv :%d (w/Padding : %d) \n",
|
||||
mbox, totalBytes, totalwPadding));
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static A_STATUS DoOneMboxHWTest(AR6K_DEVICE *pDev, int mbox)
|
||||
{
|
||||
A_STATUS status;
|
||||
|
||||
do {
|
||||
/* send out buffers */
|
||||
status = SendBuffers(pDev,mbox);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Sending buffers Failed : %d mbox:%d\n",status,mbox));
|
||||
break;
|
||||
}
|
||||
|
||||
/* go get them, this will block */
|
||||
status = RecvBuffers(pDev, mbox);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Recv buffers Failed : %d mbox:%d\n",status,mbox));
|
||||
break;
|
||||
}
|
||||
|
||||
/* check the returned data patterns */
|
||||
if (!CheckBuffers()) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer Verify Failed : mbox:%d\n",mbox));
|
||||
status = A_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" Send/Recv success! mailbox : %d \n",mbox));
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* here is where the test starts */
|
||||
A_STATUS DoMboxHWTest(AR6K_DEVICE *pDev)
|
||||
{
|
||||
int i;
|
||||
A_STATUS status;
|
||||
int credits = 0;
|
||||
A_UINT8 params[4];
|
||||
int numBufs;
|
||||
int bufferSize;
|
||||
A_UINT16 temp;
|
||||
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest START - \n"));
|
||||
|
||||
do {
|
||||
/* get the addresses for all 4 mailboxes */
|
||||
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
|
||||
g_MailboxAddrs, sizeof(g_MailboxAddrs));
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* get the block sizes */
|
||||
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
|
||||
g_BlockSizes, sizeof(g_BlockSizes));
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* note, the HIF layer usually reports mbox 0 to have a block size of
|
||||
* 1, but our test wants to run in block-mode for all mailboxes, so we treat all mailboxes
|
||||
* the same. */
|
||||
g_BlockSizes[0] = g_BlockSizes[1];
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Block Size to use: %d \n",g_BlockSizes[0]));
|
||||
|
||||
if (g_BlockSizes[1] > BUFFER_BLOCK_PAD) {
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("%d Block size is too large for buffer pad %d\n",
|
||||
g_BlockSizes[1], BUFFER_BLOCK_PAD));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for target.... \n"));
|
||||
|
||||
/* the target lets us know it is ready by giving us 1 credit on
|
||||
* mailbox 0 */
|
||||
status = GetCredits(pDev, 0, &credits);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait for target ready \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Target is ready ...\n"));
|
||||
|
||||
/* read the first 4 scratch registers */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
SCRATCH_ADDRESS,
|
||||
params,
|
||||
4,
|
||||
HIF_RD_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait get parameters \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
numBufs = params[0];
|
||||
bufferSize = (int)(((A_UINT16)params[2] << 8) | (A_UINT16)params[1]);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE,
|
||||
("Target parameters: bufs per mailbox:%d, buffer size:%d bytes (total space: %d, minimum required space (w/padding): %d) \n",
|
||||
numBufs, bufferSize, (numBufs * bufferSize), TOTAL_BYTES));
|
||||
|
||||
if ((numBufs * bufferSize) < TOTAL_BYTES) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Not Enough buffer space to run test! need:%d, got:%d \n",
|
||||
TOTAL_BYTES, (numBufs*bufferSize)));
|
||||
status = A_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
temp = GetEndMarker();
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
SCRATCH_ADDRESS + 4,
|
||||
(A_UINT8 *)&temp,
|
||||
2,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write end marker \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("End Marker: 0x%X \n",temp));
|
||||
|
||||
temp = (A_UINT16)g_BlockSizes[1];
|
||||
/* convert to a mask */
|
||||
temp = temp - 1;
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
SCRATCH_ADDRESS + 6,
|
||||
(A_UINT8 *)&temp,
|
||||
2,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write block mask \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Set Block Mask: 0x%X \n",temp));
|
||||
|
||||
/* execute the test on each mailbox */
|
||||
for (i = 0; i < AR6K_MAILBOXES; i++) {
|
||||
status = DoOneMboxHWTest(pDev, i);
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (status == A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - SUCCESS! - \n"));
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - FAILED! - \n"));
|
||||
}
|
||||
/* don't let HTC_Start continue, the target is actually not running any HTC code */
|
||||
return A_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AR6K_H_
|
||||
#define AR6K_H_
|
||||
|
||||
#define AR6K_MAILBOXES 4
|
||||
|
||||
/* HTC runs over mailbox 0 */
|
||||
#define HTC_MAILBOX 0
|
||||
|
||||
#define AR6K_TARGET_DEBUG_INTR_MASK 0x01
|
||||
|
||||
#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
|
||||
INT_STATUS_ENABLE_CPU_MASK | \
|
||||
INT_STATUS_ENABLE_COUNTER_MASK)
|
||||
|
||||
//#define MBOXHW_UNIT_TEST 1
|
||||
|
||||
#include "athstartpack.h"
|
||||
typedef PREPACK struct _AR6K_IRQ_PROC_REGISTERS {
|
||||
A_UINT8 host_int_status;
|
||||
A_UINT8 cpu_int_status;
|
||||
A_UINT8 error_int_status;
|
||||
A_UINT8 counter_int_status;
|
||||
A_UINT8 mbox_frame;
|
||||
A_UINT8 rx_lookahead_valid;
|
||||
A_UINT8 hole[2];
|
||||
A_UINT32 rx_lookahead[2];
|
||||
} POSTPACK AR6K_IRQ_PROC_REGISTERS;
|
||||
|
||||
#define AR6K_IRQ_PROC_REGS_SIZE sizeof(AR6K_IRQ_PROC_REGISTERS)
|
||||
|
||||
|
||||
|
||||
typedef PREPACK struct _AR6K_IRQ_ENABLE_REGISTERS {
|
||||
A_UINT8 int_status_enable;
|
||||
A_UINT8 cpu_int_status_enable;
|
||||
A_UINT8 error_status_enable;
|
||||
A_UINT8 counter_int_status_enable;
|
||||
} POSTPACK AR6K_IRQ_ENABLE_REGISTERS;
|
||||
|
||||
#include "athendpack.h"
|
||||
|
||||
#define AR6K_IRQ_ENABLE_REGS_SIZE sizeof(AR6K_IRQ_ENABLE_REGISTERS)
|
||||
|
||||
#define AR6K_REG_IO_BUFFER_SIZE 32
|
||||
#define AR6K_MAX_REG_IO_BUFFERS 8
|
||||
|
||||
/* buffers for ASYNC I/O */
|
||||
typedef struct AR6K_ASYNC_REG_IO_BUFFER {
|
||||
HTC_PACKET HtcPacket; /* we use an HTC packet as a wrapper for our async register-based I/O */
|
||||
A_UINT8 Buffer[AR6K_REG_IO_BUFFER_SIZE];
|
||||
} AR6K_ASYNC_REG_IO_BUFFER;
|
||||
|
||||
typedef struct _AR6K_DEVICE {
|
||||
A_MUTEX_T Lock;
|
||||
AR6K_IRQ_PROC_REGISTERS IrqProcRegisters;
|
||||
AR6K_IRQ_ENABLE_REGISTERS IrqEnableRegisters;
|
||||
void *HIFDevice;
|
||||
A_UINT32 BlockSize;
|
||||
A_UINT32 BlockMask;
|
||||
A_UINT32 MailboxAddress;
|
||||
HIF_PENDING_EVENTS_FUNC GetPendingEventsFunc;
|
||||
void *HTCContext;
|
||||
HTC_PACKET_QUEUE RegisterIOList;
|
||||
AR6K_ASYNC_REG_IO_BUFFER RegIOBuffers[AR6K_MAX_REG_IO_BUFFERS];
|
||||
void (*TargetFailureCallback)(void *Context);
|
||||
A_STATUS (*MessagePendingCallback)(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc);
|
||||
HIF_DEVICE_IRQ_PROCESSING_MODE HifIRQProcessingMode;
|
||||
HIF_MASK_UNMASK_RECV_EVENT HifMaskUmaskRecvEvent;
|
||||
} AR6K_DEVICE;
|
||||
|
||||
#define IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pDev) ((pDev)->HifIRQProcessingMode != HIF_DEVICE_IRQ_SYNC_ONLY)
|
||||
|
||||
A_STATUS DevSetup(AR6K_DEVICE *pDev);
|
||||
A_STATUS DevUnmaskInterrupts(AR6K_DEVICE *pDev);
|
||||
A_STATUS DevMaskInterrupts(AR6K_DEVICE *pDev);
|
||||
A_STATUS DevPollMboxMsgRecv(AR6K_DEVICE *pDev,
|
||||
A_UINT32 *pLookAhead,
|
||||
int TimeoutMS);
|
||||
A_STATUS DevRWCompletionHandler(void *context, A_STATUS status);
|
||||
A_STATUS DevDsrHandler(void *context);
|
||||
A_STATUS DevCheckPendingRecvMsgsAsync(void *context);
|
||||
void DevDumpRegisters(AR6K_IRQ_PROC_REGISTERS *pIrqProcRegs,
|
||||
AR6K_IRQ_ENABLE_REGISTERS *pIrqEnableRegs);
|
||||
|
||||
#define DEV_STOP_RECV_ASYNC TRUE
|
||||
#define DEV_STOP_RECV_SYNC FALSE
|
||||
#define DEV_ENABLE_RECV_ASYNC TRUE
|
||||
#define DEV_ENABLE_RECV_SYNC FALSE
|
||||
A_STATUS DevStopRecv(AR6K_DEVICE *pDev, A_BOOL ASyncMode);
|
||||
A_STATUS DevEnableRecv(AR6K_DEVICE *pDev, A_BOOL ASyncMode);
|
||||
|
||||
static INLINE A_STATUS DevSendPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 SendLength) {
|
||||
A_UINT32 paddedLength;
|
||||
A_BOOL sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
|
||||
A_STATUS status;
|
||||
|
||||
/* adjust the length to be a multiple of block size if appropriate */
|
||||
paddedLength = (SendLength + (pDev->BlockMask)) &
|
||||
(~(pDev->BlockMask));
|
||||
#if 0 // BufferLength may not be set in , fix this...
|
||||
if (paddedLength > pPacket->BufferLength) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
if (pPacket->Completion != NULL) {
|
||||
COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
|
||||
}
|
||||
return A_EINVAL;
|
||||
}
|
||||
#endif
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("DevSendPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n",
|
||||
paddedLength,
|
||||
pDev->MailboxAddress,
|
||||
sync ? "SYNC" : "ASYNC"));
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
pDev->MailboxAddress,
|
||||
pPacket->pBuffer,
|
||||
paddedLength, /* the padded length */
|
||||
sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC,
|
||||
sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
|
||||
|
||||
if (sync) {
|
||||
pPacket->Status = status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static INLINE A_STATUS DevRecvPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 RecvLength) {
|
||||
A_UINT32 paddedLength;
|
||||
A_STATUS status;
|
||||
A_BOOL sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
|
||||
|
||||
/* adjust the length to be a multiple of block size if appropriate */
|
||||
paddedLength = (RecvLength + (pDev->BlockMask)) &
|
||||
(~(pDev->BlockMask));
|
||||
if (paddedLength > pPacket->BufferLength) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("DevRecvPacket, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n",
|
||||
paddedLength,RecvLength,pPacket->BufferLength));
|
||||
if (pPacket->Completion != NULL) {
|
||||
COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
|
||||
}
|
||||
return A_EINVAL;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
|
||||
("DevRecvPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n",
|
||||
paddedLength,
|
||||
pDev->MailboxAddress,
|
||||
sync ? "SYNC" : "ASYNC"));
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
pDev->MailboxAddress,
|
||||
pPacket->pBuffer,
|
||||
paddedLength,
|
||||
sync ? HIF_RD_SYNC_BLOCK_INC : HIF_RD_ASYNC_BLOCK_INC,
|
||||
sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
|
||||
|
||||
if (sync) {
|
||||
pPacket->Status = status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef MBOXHW_UNIT_TEST
|
||||
A_STATUS DoMboxHWTest(AR6K_DEVICE *pDev);
|
||||
#endif
|
||||
|
||||
#endif /*AR6K_H_*/
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* AR6K Driver layer event handling (i.e. interrupts, message polling)
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "AR6Khwreg.h"
|
||||
#include "a_osapi.h"
|
||||
#include "a_debug.h"
|
||||
#include "hif.h"
|
||||
#include "htc_packet.h"
|
||||
#include "ar6k.h"
|
||||
|
||||
extern void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket);
|
||||
extern HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev);
|
||||
|
||||
static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev);
|
||||
|
||||
#define DELAY_PER_INTERVAL_MS 10 /* 10 MS delay per polling interval */
|
||||
|
||||
/* completion routine for ALL HIF layer async I/O */
|
||||
A_STATUS DevRWCompletionHandler(void *context, A_STATUS status)
|
||||
{
|
||||
HTC_PACKET *pPacket = (HTC_PACKET *)context;
|
||||
|
||||
COMPLETE_HTC_PACKET(pPacket,status);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/* mailbox recv message polling */
|
||||
A_STATUS DevPollMboxMsgRecv(AR6K_DEVICE *pDev,
|
||||
A_UINT32 *pLookAhead,
|
||||
int TimeoutMS)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
int timeout = TimeoutMS/DELAY_PER_INTERVAL_MS;
|
||||
|
||||
AR_DEBUG_ASSERT(timeout > 0);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevPollMboxMsgRecv \n"));
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
if (pDev->GetPendingEventsFunc != NULL)
|
||||
{
|
||||
|
||||
HIF_PENDING_EVENTS_INFO events;
|
||||
|
||||
/* the HIF layer uses a special mechanism to get events, do this
|
||||
* synchronously */
|
||||
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
|
||||
&events,
|
||||
NULL);
|
||||
if (A_FAILED(status))
|
||||
{
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get pending events \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (events.Events & HIF_RECV_MSG_AVAIL)
|
||||
{
|
||||
/* there is a message available, the lookahead should be valid now */
|
||||
*pLookAhead = events.LookAhead;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* this is the standard HIF way.... */
|
||||
/* load the register table */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
HOST_INT_STATUS_ADDRESS,
|
||||
(A_UINT8 *)&pDev->IrqProcRegisters,
|
||||
AR6K_IRQ_PROC_REGS_SIZE,
|
||||
HIF_RD_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (A_FAILED(status))
|
||||
{
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to read register table \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for MBOX data and valid lookahead */
|
||||
if (pDev->IrqProcRegisters.host_int_status & (1 << HTC_MAILBOX))
|
||||
{
|
||||
if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX))
|
||||
{
|
||||
/* mailbox has a message and the look ahead is valid */
|
||||
*pLookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
timeout--;
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout waiting for recv message \n"));
|
||||
status = A_ERROR;
|
||||
|
||||
/* check if the target asserted */
|
||||
if ( pDev->IrqProcRegisters.counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
|
||||
/* target signaled an assert, process this pending interrupt
|
||||
* this will call the target failure handler */
|
||||
DevServiceDebugInterrupt(pDev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* delay a little */
|
||||
msleep(DELAY_PER_INTERVAL_MS);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Retry Mbox Poll : %d \n",timeout));
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevPollMboxMsgRecv \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static A_STATUS DevServiceCPUInterrupt(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT8 cpu_int_status;
|
||||
A_UINT8 regBuffer[4];
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n"));
|
||||
cpu_int_status = pDev->IrqProcRegisters.cpu_int_status &
|
||||
pDev->IrqEnableRegisters.cpu_int_status_enable;
|
||||
AR_DEBUG_ASSERT(cpu_int_status);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
|
||||
cpu_int_status));
|
||||
|
||||
/* Clear the interrupt */
|
||||
pDev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; /* W1C */
|
||||
|
||||
/* set up the register transfer buffer to hit the register 4 times , this is done
|
||||
* to make the access 4-byte aligned to mitigate issues with host bus interconnects that
|
||||
* restrict bus transfer lengths to be a multiple of 4-bytes */
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
regBuffer[0] = cpu_int_status;
|
||||
/* the remaining 4 values are set to zero which have no-effect */
|
||||
regBuffer[1] = 0;
|
||||
regBuffer[2] = 0;
|
||||
regBuffer[3] = 0;
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
CPU_INT_STATUS_ADDRESS,
|
||||
regBuffer,
|
||||
4,
|
||||
HIF_WR_SYNC_BYTE_FIX,
|
||||
NULL);
|
||||
|
||||
AR_DEBUG_ASSERT(status == A_OK);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static A_STATUS DevServiceErrorInterrupt(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT8 error_int_status;
|
||||
A_UINT8 regBuffer[4];
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error Interrupt\n"));
|
||||
error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F;
|
||||
AR_DEBUG_ASSERT(error_int_status);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
|
||||
error_int_status));
|
||||
|
||||
if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
|
||||
/* Wakeup */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n"));
|
||||
}
|
||||
|
||||
if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
|
||||
/* Rx Underflow */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n"));
|
||||
}
|
||||
|
||||
if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
|
||||
/* Tx Overflow */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n"));
|
||||
}
|
||||
|
||||
/* Clear the interrupt */
|
||||
pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */
|
||||
|
||||
/* set up the register transfer buffer to hit the register 4 times , this is done
|
||||
* to make the access 4-byte aligned to mitigate issues with host bus interconnects that
|
||||
* restrict bus transfer lengths to be a multiple of 4-bytes */
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
regBuffer[0] = error_int_status;
|
||||
/* the remaining 4 values are set to zero which have no-effect */
|
||||
regBuffer[1] = 0;
|
||||
regBuffer[2] = 0;
|
||||
regBuffer[3] = 0;
|
||||
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
ERROR_INT_STATUS_ADDRESS,
|
||||
regBuffer,
|
||||
4,
|
||||
HIF_WR_SYNC_BYTE_FIX,
|
||||
NULL);
|
||||
|
||||
AR_DEBUG_ASSERT(status == A_OK);
|
||||
return status;
|
||||
}
|
||||
|
||||
static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_UINT32 dummy;
|
||||
A_STATUS status;
|
||||
|
||||
/* Send a target failure event to the application */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n"));
|
||||
|
||||
if (pDev->TargetFailureCallback != NULL) {
|
||||
pDev->TargetFailureCallback(pDev->HTCContext);
|
||||
}
|
||||
|
||||
/* clear the interrupt , the debug error interrupt is
|
||||
* counter 0 */
|
||||
/* read counter to clear interrupt */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
COUNT_DEC_ADDRESS,
|
||||
(A_UINT8 *)&dummy,
|
||||
4,
|
||||
HIF_RD_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
AR_DEBUG_ASSERT(status == A_OK);
|
||||
return status;
|
||||
}
|
||||
|
||||
static A_STATUS DevServiceCounterInterrupt(AR6K_DEVICE *pDev)
|
||||
{
|
||||
A_UINT8 counter_int_status;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
|
||||
|
||||
counter_int_status = pDev->IrqProcRegisters.counter_int_status &
|
||||
pDev->IrqEnableRegisters.counter_int_status_enable;
|
||||
|
||||
AR_DEBUG_ASSERT(counter_int_status);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
|
||||
counter_int_status));
|
||||
|
||||
/* Check if the debug interrupt is pending */
|
||||
if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
|
||||
return DevServiceDebugInterrupt(pDev);
|
||||
}
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/* callback when our fetch to get interrupt status registers completes */
|
||||
static void DevGetEventAsyncHandler(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
|
||||
A_UINT32 lookAhead = 0;
|
||||
A_BOOL otherInts = FALSE;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
|
||||
|
||||
do {
|
||||
|
||||
if (A_FAILED(pPacket->Status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" GetEvents I/O request failed, status:%d \n", pPacket->Status));
|
||||
/* bail out, don't unmask HIF interrupt */
|
||||
break;
|
||||
}
|
||||
|
||||
if (pDev->GetPendingEventsFunc != NULL) {
|
||||
/* the HIF layer collected the information for us */
|
||||
HIF_PENDING_EVENTS_INFO *pEvents = (HIF_PENDING_EVENTS_INFO *)pPacket->pBuffer;
|
||||
if (pEvents->Events & HIF_RECV_MSG_AVAIL) {
|
||||
lookAhead = pEvents->LookAhead;
|
||||
if (0 == lookAhead) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n"));
|
||||
}
|
||||
}
|
||||
if (pEvents->Events & HIF_OTHER_EVENTS) {
|
||||
otherInts = TRUE;
|
||||
}
|
||||
} else {
|
||||
/* standard interrupt table handling.... */
|
||||
AR6K_IRQ_PROC_REGISTERS *pReg = (AR6K_IRQ_PROC_REGISTERS *)pPacket->pBuffer;
|
||||
A_UINT8 host_int_status;
|
||||
|
||||
host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable;
|
||||
|
||||
if (host_int_status & (1 << HTC_MAILBOX)) {
|
||||
host_int_status &= ~(1 << HTC_MAILBOX);
|
||||
if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) {
|
||||
/* mailbox has a message and the look ahead is valid */
|
||||
lookAhead = pReg->rx_lookahead[HTC_MAILBOX];
|
||||
if (0 == lookAhead) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host_int_status) {
|
||||
/* there are other interrupts to handle */
|
||||
otherInts = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (otherInts || (lookAhead == 0)) {
|
||||
/* if there are other interrupts to process, we cannot do this in the async handler so
|
||||
* ack the interrupt which will cause our sync handler to run again
|
||||
* if however there are no more messages, we can now ack the interrupt */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
(" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n",
|
||||
otherInts, lookAhead));
|
||||
HIFAckInterrupt(pDev->HIFDevice);
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
(" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n",
|
||||
lookAhead));
|
||||
/* lookahead is non-zero and there are no other interrupts to service,
|
||||
* go get the next message */
|
||||
pDev->MessagePendingCallback(pDev->HTCContext, lookAhead, NULL);
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
/* free this IO packet */
|
||||
AR6KFreeIOPacket(pDev,pPacket);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n"));
|
||||
}
|
||||
|
||||
/* called by the HTC layer when it wants us to check if the device has any more pending
|
||||
* recv messages, this starts off a series of async requests to read interrupt registers */
|
||||
A_STATUS DevCheckPendingRecvMsgsAsync(void *context)
|
||||
{
|
||||
AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
|
||||
A_STATUS status = A_OK;
|
||||
HTC_PACKET *pIOPacket;
|
||||
|
||||
/* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can
|
||||
* cause us to switch contexts */
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%X)\n", (A_UINT32)pDev));
|
||||
|
||||
do {
|
||||
|
||||
if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
|
||||
/* break the async processing chain right here, no need to continue.
|
||||
* The DevDsrHandler() will handle things in a loop when things are driven
|
||||
* synchronously */
|
||||
break;
|
||||
}
|
||||
/* first allocate one of our HTC packets we created for async I/O
|
||||
* we reuse HTC packet definitions so that we can use the completion mechanism
|
||||
* in DevRWCompletionHandler() */
|
||||
pIOPacket = AR6KAllocIOPacket(pDev);
|
||||
|
||||
if (NULL == pIOPacket) {
|
||||
/* there should be only 1 asynchronous request out at a time to read these registers
|
||||
* so this should actually never happen */
|
||||
status = A_NO_MEMORY;
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* stick in our completion routine when the I/O operation completes */
|
||||
pIOPacket->Completion = DevGetEventAsyncHandler;
|
||||
pIOPacket->pContext = pDev;
|
||||
|
||||
if (pDev->GetPendingEventsFunc) {
|
||||
/* HIF layer has it's own mechanism, pass the IO to it.. */
|
||||
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
|
||||
(HIF_PENDING_EVENTS_INFO *)pIOPacket->pBuffer,
|
||||
pIOPacket);
|
||||
|
||||
} else {
|
||||
/* standard way, read the interrupt register table asynchronously again */
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
HOST_INT_STATUS_ADDRESS,
|
||||
pIOPacket->pBuffer,
|
||||
AR6K_IRQ_PROC_REGS_SIZE,
|
||||
HIF_RD_ASYNC_BYTE_INC,
|
||||
pIOPacket);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n"));
|
||||
} while (FALSE);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* process pending interrupts synchronously */
|
||||
static A_STATUS ProcessPendingIRQs(AR6K_DEVICE *pDev, A_BOOL *pDone, A_BOOL *pASyncProcessing)
|
||||
{
|
||||
A_STATUS status = A_OK;
|
||||
A_UINT8 host_int_status = 0;
|
||||
A_UINT32 lookAhead = 0;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%X)\n", (A_UINT32)pDev));
|
||||
|
||||
/*** NOTE: the HIF implementation guarantees that the context of this call allows
|
||||
* us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
|
||||
* can block or switch thread/task ontexts.
|
||||
* This is a fully schedulable context.
|
||||
* */
|
||||
do {
|
||||
|
||||
if (pDev->GetPendingEventsFunc != NULL) {
|
||||
HIF_PENDING_EVENTS_INFO events;
|
||||
|
||||
/* the HIF layer uses a special mechanism to get events
|
||||
* get this synchronously */
|
||||
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
|
||||
&events,
|
||||
NULL);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (events.Events & HIF_RECV_MSG_AVAIL) {
|
||||
lookAhead = events.LookAhead;
|
||||
if (0 == lookAhead) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(events.Events & HIF_OTHER_EVENTS) ||
|
||||
!(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
|
||||
/* no need to read the register table, no other interesting interrupts.
|
||||
* Some interfaces (like SPI) can shadow interrupt sources without
|
||||
* requiring the host to do a full table read */
|
||||
break;
|
||||
}
|
||||
|
||||
/* otherwise fall through and read the register table */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the first 28 bytes of the HTC register table. This will yield us
|
||||
* the value of different int status registers and the lookahead
|
||||
* registers.
|
||||
* length = sizeof(int_status) + sizeof(cpu_int_status) +
|
||||
* sizeof(error_int_status) + sizeof(counter_int_status) +
|
||||
* sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
|
||||
* sizeof(hole) + sizeof(rx_lookahead) +
|
||||
* sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
|
||||
* sizeof(error_status_enable) +
|
||||
* sizeof(counter_int_status_enable);
|
||||
*
|
||||
*/
|
||||
status = HIFReadWrite(pDev->HIFDevice,
|
||||
HOST_INT_STATUS_ADDRESS,
|
||||
(A_UINT8 *)&pDev->IrqProcRegisters,
|
||||
AR6K_IRQ_PROC_REGS_SIZE,
|
||||
HIF_RD_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
|
||||
DevDumpRegisters(&pDev->IrqProcRegisters,
|
||||
&pDev->IrqEnableRegisters);
|
||||
}
|
||||
|
||||
/* Update only those registers that are enabled */
|
||||
host_int_status = pDev->IrqProcRegisters.host_int_status &
|
||||
pDev->IrqEnableRegisters.int_status_enable;
|
||||
|
||||
if (NULL == pDev->GetPendingEventsFunc) {
|
||||
/* only look at mailbox status if the HIF layer did not provide this function,
|
||||
* on some HIF interfaces reading the RX lookahead is not valid to do */
|
||||
if (host_int_status & (1 << HTC_MAILBOX)) {
|
||||
/* mask out pending mailbox value, we use "lookAhead" as the real flag for
|
||||
* mailbox processing below */
|
||||
host_int_status &= ~(1 << HTC_MAILBOX);
|
||||
if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
|
||||
/* mailbox has a message and the look ahead is valid */
|
||||
lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
|
||||
if (0 == lookAhead) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
|
||||
host_int_status &= ~(1 << HTC_MAILBOX);
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
|
||||
do {
|
||||
|
||||
/* did the interrupt status fetches succeed? */
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((0 == host_int_status) && (0 == lookAhead)) {
|
||||
/* nothing to process, the caller can use this to break out of a loop */
|
||||
*pDone = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lookAhead != 0) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
|
||||
/* Mailbox Interrupt, the HTC layer may issue async requests to empty the
|
||||
* mailbox...
|
||||
* When emptying the recv mailbox we use the async handler above called from the
|
||||
* completion routine of the callers read request. This can improve performance
|
||||
* by reducing context switching when we rapidly pull packets */
|
||||
status = pDev->MessagePendingCallback(pDev->HTCContext, lookAhead, pASyncProcessing);
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* now handle the rest of them */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
|
||||
(" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
|
||||
host_int_status));
|
||||
|
||||
if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
|
||||
/* CPU Interrupt */
|
||||
status = DevServiceCPUInterrupt(pDev);
|
||||
if (A_FAILED(status)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
|
||||
/* Error Interrupt */
|
||||
status = DevServiceErrorInterrupt(pDev);
|
||||
if (A_FAILED(status)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
|
||||
/* Counter Interrupt */
|
||||
status = DevServiceCounterInterrupt(pDev);
|
||||
if (A_FAILED(status)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
|
||||
*pDone, *pASyncProcessing, status));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/
|
||||
A_STATUS DevDsrHandler(void *context)
|
||||
{
|
||||
AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
|
||||
A_STATUS status = A_OK;
|
||||
A_BOOL done = FALSE;
|
||||
A_BOOL asyncProc = FALSE;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
|
||||
|
||||
|
||||
while (!done) {
|
||||
status = ProcessPendingIRQs(pDev, &done, &asyncProc);
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
|
||||
/* the HIF layer does not allow async IRQ processing, override the asyncProc flag */
|
||||
asyncProc = FALSE;
|
||||
/* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers.
|
||||
* this has a nice side effect of blocking us until all async read requests are completed.
|
||||
* This behavior is required on some HIF implementations that do not allow ASYNC
|
||||
* processing in interrupt handlers (like Windows CE) */
|
||||
}
|
||||
|
||||
if (asyncProc) {
|
||||
/* the function performed some async I/O for performance, we
|
||||
need to exit the ISR immediately, the check below will prevent the interrupt from being
|
||||
Ack'd while we handle it asynchronously */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (A_SUCCESS(status) && !asyncProc) {
|
||||
/* Ack the interrupt only if :
|
||||
* 1. we did not get any errors in processing interrupts
|
||||
* 2. there are no outstanding async processing requests */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n"));
|
||||
HIFAckInterrupt(pDev->HIFDevice);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "htc_internal.h"
|
||||
|
||||
|
||||
static HTC_INIT_INFO HTCInitInfo = {NULL,NULL,NULL};
|
||||
static A_BOOL HTCInitialized = FALSE;
|
||||
|
||||
static A_STATUS HTCTargetInsertedHandler(void *hif_handle);
|
||||
static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status);
|
||||
static void HTCReportFailure(void *Context);
|
||||
|
||||
/* Initializes the HTC layer */
|
||||
A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo)
|
||||
{
|
||||
HTC_CALLBACKS htcCallbacks;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n"));
|
||||
if (HTCInitialized) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO));
|
||||
|
||||
A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS));
|
||||
|
||||
/* setup HIF layer callbacks */
|
||||
htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler;
|
||||
htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler;
|
||||
/* the device layer handles these */
|
||||
htcCallbacks.rwCompletionHandler = DevRWCompletionHandler;
|
||||
htcCallbacks.dsrHandler = DevDsrHandler;
|
||||
HIFInit(&htcCallbacks);
|
||||
HTCInitialized = TRUE;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList)
|
||||
{
|
||||
LOCK_HTC(target);
|
||||
HTC_PACKET_ENQUEUE(pList,pPacket);
|
||||
UNLOCK_HTC(target);
|
||||
}
|
||||
|
||||
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList)
|
||||
{
|
||||
HTC_PACKET *pPacket;
|
||||
|
||||
LOCK_HTC(target);
|
||||
pPacket = HTC_PACKET_DEQUEUE(pList);
|
||||
UNLOCK_HTC(target);
|
||||
|
||||
return pPacket;
|
||||
}
|
||||
|
||||
/* cleanup the HTC instance */
|
||||
static void HTCCleanup(HTC_TARGET *target)
|
||||
{
|
||||
if (A_IS_MUTEX_VALID(&target->HTCLock)) {
|
||||
A_MUTEX_DELETE(&target->HTCLock);
|
||||
}
|
||||
|
||||
if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
|
||||
A_MUTEX_DELETE(&target->HTCRxLock);
|
||||
}
|
||||
|
||||
if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
|
||||
A_MUTEX_DELETE(&target->HTCTxLock);
|
||||
}
|
||||
/* free our instance */
|
||||
A_FREE(target);
|
||||
}
|
||||
|
||||
/* registered target arrival callback from the HIF layer */
|
||||
static A_STATUS HTCTargetInsertedHandler(void *hif_handle)
|
||||
{
|
||||
HTC_TARGET *target = NULL;
|
||||
A_STATUS status;
|
||||
int i;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n"));
|
||||
|
||||
do {
|
||||
|
||||
/* allocate target memory */
|
||||
if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
|
||||
status = A_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
A_MEMZERO(target, sizeof(HTC_TARGET));
|
||||
A_MUTEX_INIT(&target->HTCLock);
|
||||
A_MUTEX_INIT(&target->HTCRxLock);
|
||||
A_MUTEX_INIT(&target->HTCTxLock);
|
||||
INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
|
||||
INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
|
||||
|
||||
/* give device layer the hif device handle */
|
||||
target->Device.HIFDevice = hif_handle;
|
||||
/* give the device layer our context (for event processing)
|
||||
* the device layer will register it's own context with HIF
|
||||
* so we need to set this so we can fetch it in the target remove handler */
|
||||
target->Device.HTCContext = target;
|
||||
/* set device layer target failure callback */
|
||||
target->Device.TargetFailureCallback = HTCReportFailure;
|
||||
/* set device layer recv message pending callback */
|
||||
target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
|
||||
target->EpWaitingForBuffers = ENDPOINT_MAX;
|
||||
|
||||
/* setup device layer */
|
||||
status = DevSetup(&target->Device);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* carve up buffers/packets for control messages */
|
||||
for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
|
||||
HTC_PACKET *pControlPacket;
|
||||
pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
|
||||
SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
|
||||
target,
|
||||
target->HTCControlBuffers[i].Buffer,
|
||||
HTC_CONTROL_BUFFER_SIZE,
|
||||
ENDPOINT_0);
|
||||
HTC_FREE_CONTROL_RX(target,pControlPacket);
|
||||
}
|
||||
|
||||
for (;i < NUM_CONTROL_BUFFERS;i++) {
|
||||
HTC_PACKET *pControlPacket;
|
||||
pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
|
||||
INIT_HTC_PACKET_INFO(pControlPacket,
|
||||
target->HTCControlBuffers[i].Buffer,
|
||||
HTC_CONTROL_BUFFER_SIZE);
|
||||
HTC_FREE_CONTROL_TX(target,pControlPacket);
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_SUCCESS(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n"));
|
||||
/* announce ourselves */
|
||||
HTCInitInfo.AddInstance((HTC_HANDLE)target);
|
||||
} else {
|
||||
if (target != NULL) {
|
||||
HTCCleanup(target);
|
||||
}
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* registered removal callback from the HIF layer */
|
||||
static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status)
|
||||
{
|
||||
HTC_TARGET *target;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle));
|
||||
|
||||
if (NULL == handle) {
|
||||
/* this could be NULL in the event that target initialization failed */
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
target = ((AR6K_DEVICE *)handle)->HTCContext;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" removing target:0x%X instance:0x%X ... \n",
|
||||
(A_UINT32)target, (A_UINT32)target->pInstanceContext));
|
||||
|
||||
if (target->pInstanceContext != NULL) {
|
||||
/* let upper layer know, it needs to call HTCStop() */
|
||||
HTCInitInfo.DeleteInstance(target->pInstanceContext);
|
||||
}
|
||||
|
||||
HIFShutDownDevice(target->Device.HIFDevice);
|
||||
|
||||
HTCCleanup(target);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n"));
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/* get the low level HIF device for the caller , the caller may wish to do low level
|
||||
* HIF requests */
|
||||
void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
return target->Device.HIFDevice;
|
||||
}
|
||||
|
||||
/* set the instance block for this HTC handle, so that on removal, the blob can be
|
||||
* returned to the caller */
|
||||
void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
|
||||
target->pInstanceContext = Instance;
|
||||
}
|
||||
|
||||
/* wait for the target to arrive (sends HTC Ready message)
|
||||
* this operation is fully synchronous and the message is polled for */
|
||||
A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
A_STATUS status;
|
||||
HTC_PACKET *pPacket = NULL;
|
||||
HTC_READY_MSG *pRdyMsg;
|
||||
HTC_SERVICE_CONNECT_REQ connect;
|
||||
HTC_SERVICE_CONNECT_RESP resp;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target));
|
||||
|
||||
do {
|
||||
|
||||
#ifdef MBOXHW_UNIT_TEST
|
||||
|
||||
status = DoMboxHWTest(&target->Device);
|
||||
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* we should be getting 1 control message that the target is ready */
|
||||
status = HTCWaitforControlMessage(target, &pPacket);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
/* we controlled the buffer creation so it has to be properly aligned */
|
||||
pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer;
|
||||
|
||||
if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) ||
|
||||
(pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
|
||||
/* this message is not valid */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) {
|
||||
/* this message is not valid */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
target->TargetCredits = pRdyMsg->CreditCount;
|
||||
target->TargetCreditSize = pRdyMsg->CreditSize;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n",
|
||||
target->TargetCredits, target->TargetCreditSize));
|
||||
|
||||
/* setup our pseudo HTC control endpoint connection */
|
||||
A_MEMZERO(&connect,sizeof(connect));
|
||||
A_MEMZERO(&resp,sizeof(resp));
|
||||
connect.EpCallbacks.pContext = target;
|
||||
connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
|
||||
connect.EpCallbacks.EpRecv = HTCControlRecv;
|
||||
connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */
|
||||
connect.EpCallbacks.EpSendFull = NULL; /* not needed */
|
||||
connect.EpCallbacks.EpSendAvail = NULL; /* not needed */
|
||||
connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
|
||||
connect.ServiceID = HTC_CTRL_RSVD_SVC;
|
||||
|
||||
/* connect fake service */
|
||||
status = HTCConnectService((HTC_HANDLE)target,
|
||||
&connect,
|
||||
&resp);
|
||||
|
||||
if (!A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (pPacket != NULL) {
|
||||
HTC_FREE_CONTROL_RX(target,pPacket);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Start HTC, enable interrupts and let the target know host has finished setup */
|
||||
A_STATUS HTCStart(HTC_HANDLE HTCHandle)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
HTC_PACKET *pPacket;
|
||||
A_STATUS status;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
|
||||
|
||||
/* now that we are starting, push control receive buffers into the
|
||||
* HTC control endpoint */
|
||||
|
||||
while (1) {
|
||||
pPacket = HTC_ALLOC_CONTROL_RX(target);
|
||||
if (NULL == pPacket) {
|
||||
break;
|
||||
}
|
||||
HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
AR_DEBUG_ASSERT(target->InitCredits != NULL);
|
||||
AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
|
||||
AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
|
||||
|
||||
/* call init credits callback to do the distribution ,
|
||||
* NOTE: the first entry in the distribution list is ENDPOINT_0, so
|
||||
* we pass the start of the list after this one. */
|
||||
target->InitCredits(target->pCredDistContext,
|
||||
target->EpCreditDistributionListHead->pNext,
|
||||
target->TargetCredits);
|
||||
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
|
||||
DumpCreditDistStates(target);
|
||||
}
|
||||
|
||||
/* the caller is done connecting to services, so we can indicate to the
|
||||
* target that the setup phase is complete */
|
||||
status = HTCSendSetupComplete(target);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* unmask interrupts */
|
||||
status = DevUnmaskInterrupts(&target->Device);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
HTCStop(target);
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
|
||||
void HTCStop(HTC_HANDLE HTCHandle)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
|
||||
|
||||
/* mark that we are shutting down .. */
|
||||
target->HTCStateFlags |= HTC_STATE_STOPPING;
|
||||
|
||||
/* Masking interrupts is a synchronous operation, when this function returns
|
||||
* all pending HIF I/O has completed, we can safely flush the queues */
|
||||
DevMaskInterrupts(&target->Device);
|
||||
|
||||
/* flush all send packets */
|
||||
HTCFlushSendPkts(target);
|
||||
/* flush all recv buffers */
|
||||
HTCFlushRecvBuffers(target);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
|
||||
}
|
||||
|
||||
/* undo what was done in HTCInit() */
|
||||
void HTCShutDown(void)
|
||||
{
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n"));
|
||||
HTCInitialized = FALSE;
|
||||
/* undo HTCInit */
|
||||
HIFShutDownDevice(NULL);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n"));
|
||||
}
|
||||
|
||||
void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
DumpCreditDistStates(target);
|
||||
|
||||
UNLOCK_HTC_TX(target);
|
||||
}
|
||||
|
||||
/* report a target failure from the device, this is a callback from the device layer
|
||||
* which uses a mechanism to report errors from the target (i.e. special interrupts) */
|
||||
static void HTCReportFailure(void *Context)
|
||||
{
|
||||
HTC_TARGET *target = (HTC_TARGET *)Context;
|
||||
|
||||
target->TargetFailure = TRUE;
|
||||
|
||||
if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) {
|
||||
/* let upper layer know, it needs to call HTCStop() */
|
||||
HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
|
||||
{
|
||||
A_CHAR stream[60];
|
||||
A_UINT32 i;
|
||||
A_UINT16 offset, count;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription));
|
||||
|
||||
count = 0;
|
||||
offset = 0;
|
||||
for(i = 0; i < length; i++) {
|
||||
sprintf(stream + offset, "%2.2X ", buffer[i]);
|
||||
count ++;
|
||||
offset += 3;
|
||||
|
||||
if(count == 16) {
|
||||
count = 0;
|
||||
offset = 0;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
|
||||
A_MEMZERO(stream, 60);
|
||||
}
|
||||
}
|
||||
|
||||
if(offset != 0) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n"));
|
||||
}
|
||||
|
||||
A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
|
||||
HTC_ENDPOINT_ID Endpoint,
|
||||
HTC_ENDPOINT_STAT_ACTION Action,
|
||||
HTC_ENDPOINT_STATS *pStats)
|
||||
{
|
||||
|
||||
#ifdef HTC_EP_STAT_PROFILING
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
A_BOOL clearStats = FALSE;
|
||||
A_BOOL sample = FALSE;
|
||||
|
||||
switch (Action) {
|
||||
case HTC_EP_STAT_SAMPLE :
|
||||
sample = TRUE;
|
||||
break;
|
||||
case HTC_EP_STAT_SAMPLE_AND_CLEAR :
|
||||
sample = TRUE;
|
||||
clearStats = TRUE;
|
||||
break;
|
||||
case HTC_EP_STAT_CLEAR :
|
||||
clearStats = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
A_ASSERT(Endpoint < ENDPOINT_MAX);
|
||||
|
||||
/* lock out TX and RX while we sample and/or clear */
|
||||
LOCK_HTC_TX(target);
|
||||
LOCK_HTC_RX(target);
|
||||
|
||||
if (sample) {
|
||||
A_ASSERT(pStats != NULL);
|
||||
/* return the stats to the caller */
|
||||
A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
|
||||
}
|
||||
|
||||
if (clearStats) {
|
||||
/* reset stats */
|
||||
A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
|
||||
}
|
||||
|
||||
UNLOCK_HTC_RX(target);
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef HTC_DEBUG_H_
|
||||
#define HTC_DEBUG_H_
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* ------- Debug related stuff ------- */
|
||||
enum {
|
||||
ATH_DEBUG_SEND = 0x0001,
|
||||
ATH_DEBUG_RECV = 0x0002,
|
||||
ATH_DEBUG_SYNC = 0x0004,
|
||||
ATH_DEBUG_DUMP = 0x0008,
|
||||
ATH_DEBUG_IRQ = 0x0010,
|
||||
ATH_DEBUG_TRC = 0x0020,
|
||||
ATH_DEBUG_WARN = 0x0040,
|
||||
ATH_DEBUG_ERR = 0x0080,
|
||||
ATH_DEBUG_ANY = 0xFFFF,
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
// TODO FIX usage of A_PRINTF!
|
||||
#define AR_DEBUG_LVL_CHECK(lvl) (debughtc & (lvl))
|
||||
#define AR_DEBUG_PRINTBUF(buffer, length, desc) do { \
|
||||
if (debughtc & ATH_DEBUG_DUMP) { \
|
||||
DebugDumpBytes(buffer, length,desc); \
|
||||
} \
|
||||
} while(0)
|
||||
#define PRINTX_ARG(arg...) arg
|
||||
#define AR_DEBUG_PRINTF(flags, args) do { \
|
||||
if (debughtc & (flags)) { \
|
||||
A_PRINTF(KERN_ALERT PRINTX_ARG args); \
|
||||
} \
|
||||
} while (0)
|
||||
#define AR_DEBUG_ASSERT(test) do { \
|
||||
if (!(test)) { \
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,#test)); \
|
||||
} \
|
||||
} while(0)
|
||||
extern int debughtc;
|
||||
#else
|
||||
#define AR_DEBUG_PRINTF(flags, args)
|
||||
#define AR_DEBUG_PRINTBUF(buffer, length, desc)
|
||||
#define AR_DEBUG_ASSERT(test)
|
||||
#define AR_DEBUG_LVL_CHECK(lvl) 0
|
||||
#endif
|
||||
|
||||
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription);
|
||||
|
||||
#endif /*HTC_DEBUG_H_*/
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HTC_INTERNAL_H_
|
||||
#define _HTC_INTERNAL_H_
|
||||
|
||||
/* for debugging, uncomment this to capture the last frame header, on frame header
|
||||
* processing errors, the last frame header is dump for comparison */
|
||||
//#define HTC_CAPTURE_LAST_FRAME
|
||||
|
||||
//#define HTC_EP_STAT_PROFILING
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Header files */
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "a_debug.h"
|
||||
#include "htc.h"
|
||||
#include "htc_api.h"
|
||||
#include "bmi_msg.h"
|
||||
#include "hif.h"
|
||||
#include "ar6k.h"
|
||||
|
||||
/* HTC operational parameters */
|
||||
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
|
||||
#define HTC_TARGET_DEBUG_INTR_MASK 0x01
|
||||
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
|
||||
|
||||
typedef struct _HTC_ENDPOINT {
|
||||
HTC_SERVICE_ID ServiceID; /* service ID this endpoint is bound to
|
||||
non-zero value means this endpoint is in use */
|
||||
HTC_PACKET_QUEUE TxQueue; /* HTC frame buffer TX queue */
|
||||
HTC_PACKET_QUEUE RxBuffers; /* HTC frame buffer RX list */
|
||||
HTC_ENDPOINT_CREDIT_DIST CreditDist; /* credit distribution structure (exposed to driver layer) */
|
||||
HTC_EP_CALLBACKS EpCallBacks; /* callbacks associated with this endpoint */
|
||||
int MaxTxQueueDepth; /* max depth of the TX queue before we need to
|
||||
call driver's full handler */
|
||||
int CurrentTxQueueDepth; /* current TX queue depth */
|
||||
int MaxMsgLength; /* max length of endpoint message */
|
||||
#ifdef HTC_EP_STAT_PROFILING
|
||||
HTC_ENDPOINT_STATS EndPointStats; /* endpoint statistics */
|
||||
#endif
|
||||
} HTC_ENDPOINT;
|
||||
|
||||
#ifdef HTC_EP_STAT_PROFILING
|
||||
#define INC_HTC_EP_STAT(p,stat,count) (p)->EndPointStats.stat += (count);
|
||||
#else
|
||||
#define INC_HTC_EP_STAT(p,stat,count)
|
||||
#endif
|
||||
|
||||
#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL
|
||||
|
||||
#define NUM_CONTROL_BUFFERS 8
|
||||
#define NUM_CONTROL_TX_BUFFERS 2
|
||||
#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
|
||||
|
||||
#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH)
|
||||
|
||||
typedef struct HTC_CONTROL_BUFFER {
|
||||
HTC_PACKET HtcPacket;
|
||||
A_UINT8 Buffer[HTC_CONTROL_BUFFER_SIZE];
|
||||
} HTC_CONTROL_BUFFER;
|
||||
|
||||
/* our HTC target state */
|
||||
typedef struct _HTC_TARGET {
|
||||
HTC_ENDPOINT EndPoint[ENDPOINT_MAX];
|
||||
HTC_CONTROL_BUFFER HTCControlBuffers[NUM_CONTROL_BUFFERS];
|
||||
HTC_ENDPOINT_CREDIT_DIST *EpCreditDistributionListHead;
|
||||
HTC_PACKET_QUEUE ControlBufferTXFreeList;
|
||||
HTC_PACKET_QUEUE ControlBufferRXFreeList;
|
||||
HTC_CREDIT_DIST_CALLBACK DistributeCredits;
|
||||
HTC_CREDIT_INIT_CALLBACK InitCredits;
|
||||
void *pCredDistContext;
|
||||
int TargetCredits;
|
||||
int TargetCreditSize;
|
||||
A_MUTEX_T HTCLock;
|
||||
A_MUTEX_T HTCRxLock;
|
||||
A_MUTEX_T HTCTxLock;
|
||||
AR6K_DEVICE Device; /* AR6K - specific state */
|
||||
A_UINT32 HTCStateFlags;
|
||||
HTC_ENDPOINT_ID EpWaitingForBuffers;
|
||||
A_BOOL TargetFailure;
|
||||
void *pInstanceContext;
|
||||
#define HTC_STATE_WAIT_BUFFERS (1 << 0)
|
||||
#define HTC_STATE_STOPPING (1 << 1)
|
||||
#ifdef HTC_CAPTURE_LAST_FRAME
|
||||
HTC_FRAME_HDR LastFrameHdr; /* useful for debugging */
|
||||
A_UINT8 LastTrailer[256];
|
||||
A_UINT8 LastTrailerLength;
|
||||
#endif
|
||||
} HTC_TARGET;
|
||||
|
||||
#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING)
|
||||
#define LOCK_HTC(t) A_MUTEX_LOCK(&(t)->HTCLock);
|
||||
#define UNLOCK_HTC(t) A_MUTEX_UNLOCK(&(t)->HTCLock);
|
||||
#define LOCK_HTC_RX(t) A_MUTEX_LOCK(&(t)->HTCRxLock);
|
||||
#define UNLOCK_HTC_RX(t) A_MUTEX_UNLOCK(&(t)->HTCRxLock);
|
||||
#define LOCK_HTC_TX(t) A_MUTEX_LOCK(&(t)->HTCTxLock);
|
||||
#define UNLOCK_HTC_TX(t) A_MUTEX_UNLOCK(&(t)->HTCTxLock);
|
||||
|
||||
#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd))
|
||||
#define HTC_RECYCLE_RX_PKT(target,p) \
|
||||
{ \
|
||||
HTC_PACKET_RESET_RX(pPacket); \
|
||||
HTCAddReceivePkt((HTC_HANDLE)(target),(p)); \
|
||||
}
|
||||
|
||||
/* internal HTC functions */
|
||||
void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket);
|
||||
void HTCControlRecv(void *Context, HTC_PACKET *pPacket);
|
||||
A_STATUS HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket);
|
||||
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList);
|
||||
void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList);
|
||||
A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 Flags);
|
||||
A_STATUS HTCIssueRecv(HTC_TARGET *target, HTC_PACKET *pPacket);
|
||||
void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket);
|
||||
A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc);
|
||||
void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
|
||||
A_STATUS HTCSendSetupComplete(HTC_TARGET *target);
|
||||
void HTCFlushRecvBuffers(HTC_TARGET *target);
|
||||
void HTCFlushSendPkts(HTC_TARGET *target);
|
||||
void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist);
|
||||
void DumpCreditDistStates(HTC_TARGET *target);
|
||||
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription);
|
||||
|
||||
static INLINE HTC_PACKET *HTC_ALLOC_CONTROL_TX(HTC_TARGET *target) {
|
||||
HTC_PACKET *pPacket = HTCAllocControlBuffer(target,&target->ControlBufferTXFreeList);
|
||||
if (pPacket != NULL) {
|
||||
/* set payload pointer area with some headroom */
|
||||
pPacket->pBuffer = pPacket->pBufferStart + HTC_HDR_LENGTH;
|
||||
}
|
||||
return pPacket;
|
||||
}
|
||||
|
||||
#define HTC_FREE_CONTROL_TX(t,p) HTCFreeControlBuffer((t),(p),&(t)->ControlBufferTXFreeList)
|
||||
#define HTC_ALLOC_CONTROL_RX(t) HTCAllocControlBuffer((t),&(t)->ControlBufferRXFreeList)
|
||||
#define HTC_FREE_CONTROL_RX(t,p) \
|
||||
{ \
|
||||
HTC_PACKET_RESET_RX(p); \
|
||||
HTCFreeControlBuffer((t),(p),&(t)->ControlBufferRXFreeList); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HTC_INTERNAL_H_ */
|
|
@ -0,0 +1,703 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "htc_internal.h"
|
||||
|
||||
#define HTCIssueRecv(t, p) \
|
||||
DevRecvPacket(&(t)->Device, \
|
||||
(p), \
|
||||
(p)->ActualLength)
|
||||
|
||||
#define DO_RCV_COMPLETION(t,p,e) \
|
||||
{ \
|
||||
if ((p)->ActualLength > 0) { \
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" completing packet 0x%X (%d bytes) on ep : %d \n", \
|
||||
(A_UINT32)(p), (p)->ActualLength, (p)->Endpoint)); \
|
||||
(e)->EpCallBacks.EpRecv((e)->EpCallBacks.pContext, \
|
||||
(p)); \
|
||||
} else { \
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" recycling empty packet \n")); \
|
||||
HTC_RECYCLE_RX_PKT((t), (p)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef HTC_EP_STAT_PROFILING
|
||||
#define HTC_RX_STAT_PROFILE(t,ep,lookAhead) \
|
||||
{ \
|
||||
LOCK_HTC_RX((t)); \
|
||||
INC_HTC_EP_STAT((ep), RxReceived, 1); \
|
||||
if ((lookAhead) != 0) { \
|
||||
INC_HTC_EP_STAT((ep), RxLookAheads, 1); \
|
||||
} \
|
||||
UNLOCK_HTC_RX((t)); \
|
||||
}
|
||||
#else
|
||||
#define HTC_RX_STAT_PROFILE(t,ep,lookAhead)
|
||||
#endif
|
||||
|
||||
static INLINE A_STATUS HTCProcessTrailer(HTC_TARGET *target,
|
||||
A_UINT8 *pBuffer,
|
||||
int Length,
|
||||
A_UINT32 *pNextLookAhead,
|
||||
HTC_ENDPOINT_ID FromEndpoint)
|
||||
{
|
||||
HTC_RECORD_HDR *pRecord;
|
||||
A_UINT8 *pRecordBuf;
|
||||
HTC_LOOKAHEAD_REPORT *pLookAhead;
|
||||
A_UINT8 *pOrigBuffer;
|
||||
int origLength;
|
||||
A_STATUS status;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
|
||||
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
|
||||
AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
|
||||
}
|
||||
|
||||
pOrigBuffer = pBuffer;
|
||||
origLength = Length;
|
||||
status = A_OK;
|
||||
|
||||
while (Length > 0) {
|
||||
|
||||
if (Length < sizeof(HTC_RECORD_HDR)) {
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
/* these are byte aligned structs */
|
||||
pRecord = (HTC_RECORD_HDR *)pBuffer;
|
||||
Length -= sizeof(HTC_RECORD_HDR);
|
||||
pBuffer += sizeof(HTC_RECORD_HDR);
|
||||
|
||||
if (pRecord->Length > Length) {
|
||||
/* no room left in buffer for record */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
|
||||
pRecord->Length, pRecord->RecordID, Length));
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
/* start of record follows the header */
|
||||
pRecordBuf = pBuffer;
|
||||
|
||||
switch (pRecord->RecordID) {
|
||||
case HTC_RECORD_CREDITS:
|
||||
AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
|
||||
HTCProcessCreditRpt(target,
|
||||
(HTC_CREDIT_REPORT *)pRecordBuf,
|
||||
pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
|
||||
FromEndpoint);
|
||||
break;
|
||||
case HTC_RECORD_LOOKAHEAD:
|
||||
AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
|
||||
pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
|
||||
if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
|
||||
(pNextLookAhead != NULL)) {
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
|
||||
(" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
|
||||
pLookAhead->PreValid,
|
||||
pLookAhead->PostValid));
|
||||
|
||||
/* look ahead bytes are valid, copy them over */
|
||||
((A_UINT8 *)pNextLookAhead)[0] = pLookAhead->LookAhead[0];
|
||||
((A_UINT8 *)pNextLookAhead)[1] = pLookAhead->LookAhead[1];
|
||||
((A_UINT8 *)pNextLookAhead)[2] = pLookAhead->LookAhead[2];
|
||||
((A_UINT8 *)pNextLookAhead)[3] = pLookAhead->LookAhead[3];
|
||||
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
|
||||
DebugDumpBytes((A_UINT8 *)pNextLookAhead,4,"Next Look Ahead");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
|
||||
pRecord->RecordID, pRecord->Length));
|
||||
break;
|
||||
}
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* advance buffer past this record for next time around */
|
||||
pBuffer += pRecord->Length;
|
||||
Length -= pRecord->Length;
|
||||
}
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/* process a received message (i.e. strip off header, process any trailer data)
|
||||
* note : locks must be released when this function is called */
|
||||
static A_STATUS HTCProcessRecvHeader(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT32 *pNextLookAhead)
|
||||
{
|
||||
A_UINT8 temp;
|
||||
A_UINT8 *pBuf;
|
||||
A_STATUS status = A_OK;
|
||||
A_UINT16 payloadLen;
|
||||
A_UINT32 lookAhead;
|
||||
|
||||
pBuf = pPacket->pBuffer;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
|
||||
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
|
||||
AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
|
||||
}
|
||||
|
||||
do {
|
||||
/* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
|
||||
* retrieve 16 bit fields */
|
||||
payloadLen = A_GET_UINT16_FIELD(pBuf, HTC_FRAME_HDR, PayloadLen);
|
||||
|
||||
((A_UINT8 *)&lookAhead)[0] = pBuf[0];
|
||||
((A_UINT8 *)&lookAhead)[1] = pBuf[1];
|
||||
((A_UINT8 *)&lookAhead)[2] = pBuf[2];
|
||||
((A_UINT8 *)&lookAhead)[3] = pBuf[3];
|
||||
|
||||
if (lookAhead != pPacket->HTCReserved) {
|
||||
/* somehow the lookahead that gave us the full read length did not
|
||||
* reflect the actual header in the pending message */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCProcessRecvHeader, lookahead mismatch! \n"));
|
||||
DebugDumpBytes((A_UINT8 *)&pPacket->HTCReserved,4,"Expected Message LookAhead");
|
||||
DebugDumpBytes(pBuf,sizeof(HTC_FRAME_HDR),"Current Frame Header");
|
||||
#ifdef HTC_CAPTURE_LAST_FRAME
|
||||
DebugDumpBytes((A_UINT8 *)&target->LastFrameHdr,sizeof(HTC_FRAME_HDR),"Last Frame Header");
|
||||
if (target->LastTrailerLength != 0) {
|
||||
DebugDumpBytes(target->LastTrailer,
|
||||
target->LastTrailerLength,
|
||||
"Last trailer");
|
||||
}
|
||||
#endif
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* get flags */
|
||||
temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, Flags);
|
||||
|
||||
if (temp & HTC_FLAGS_RECV_TRAILER) {
|
||||
/* this packet has a trailer */
|
||||
|
||||
/* extract the trailer length in control byte 0 */
|
||||
temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, ControlBytes[0]);
|
||||
|
||||
if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
|
||||
payloadLen, temp));
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* process trailer data that follows HDR + application payload */
|
||||
status = HTCProcessTrailer(target,
|
||||
(pBuf + HTC_HDR_LENGTH + payloadLen - temp),
|
||||
temp,
|
||||
pNextLookAhead,
|
||||
pPacket->Endpoint);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HTC_CAPTURE_LAST_FRAME
|
||||
A_MEMCPY(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
|
||||
target->LastTrailerLength = temp;
|
||||
#endif
|
||||
/* trim length by trailer bytes */
|
||||
pPacket->ActualLength -= temp;
|
||||
}
|
||||
#ifdef HTC_CAPTURE_LAST_FRAME
|
||||
else {
|
||||
target->LastTrailerLength = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if we get to this point, the packet is good */
|
||||
/* remove header and adjust length */
|
||||
pPacket->pBuffer += HTC_HDR_LENGTH;
|
||||
pPacket->ActualLength -= HTC_HDR_LENGTH;
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
/* dump the whole packet */
|
||||
DebugDumpBytes(pBuf,pPacket->ActualLength,"BAD HTC Recv PKT");
|
||||
} else {
|
||||
#ifdef HTC_CAPTURE_LAST_FRAME
|
||||
A_MEMCPY(&target->LastFrameHdr,pBuf,sizeof(HTC_FRAME_HDR));
|
||||
#endif
|
||||
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
|
||||
if (pPacket->ActualLength > 0) {
|
||||
AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* asynchronous completion handler for recv packet fetching, when the device layer
|
||||
* completes a read request, it will call this completion handler */
|
||||
void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
HTC_TARGET *target = (HTC_TARGET *)Context;
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
A_UINT32 nextLookAhead = 0;
|
||||
A_STATUS status;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (status:%d, ep:%d) \n",
|
||||
pPacket->Status, pPacket->Endpoint));
|
||||
|
||||
AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
|
||||
pEndpoint = &target->EndPoint[pPacket->Endpoint];
|
||||
pPacket->Completion = NULL;
|
||||
|
||||
/* get completion status */
|
||||
status = pPacket->Status;
|
||||
|
||||
do {
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
|
||||
pPacket->Status, pPacket->Endpoint));
|
||||
break;
|
||||
}
|
||||
/* process the header for any trailer data */
|
||||
status = HTCProcessRecvHeader(target,pPacket,&nextLookAhead);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
/* was there a lookahead for the next packet? */
|
||||
if (nextLookAhead != 0) {
|
||||
A_STATUS nextStatus;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
|
||||
("HTCRecvCompleteHandler - next look ahead was non-zero : 0x%X \n",
|
||||
nextLookAhead));
|
||||
/* we have another packet, get the next packet fetch started (pipelined) before
|
||||
* we call into the endpoint's callback, this will start another async request */
|
||||
nextStatus = HTCRecvMessagePendingHandler(target,nextLookAhead,NULL);
|
||||
if (A_EPROTO == nextStatus) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("Next look ahead from recv header was INVALID\n"));
|
||||
DebugDumpBytes((A_UINT8 *)&nextLookAhead,
|
||||
4,
|
||||
"BAD lookahead from lookahead report");
|
||||
}
|
||||
} else {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
|
||||
("HTCRecvCompleteHandler - rechecking for more messages...\n"));
|
||||
/* if we did not get anything on the look-ahead,
|
||||
* call device layer to asynchronously re-check for messages. If we can keep the async
|
||||
* processing going we get better performance. If there is a pending message we will keep processing
|
||||
* messages asynchronously which should pipeline things nicely */
|
||||
DevCheckPendingRecvMsgsAsync(&target->Device);
|
||||
}
|
||||
|
||||
HTC_RX_STAT_PROFILE(target,pEndpoint,nextLookAhead);
|
||||
DO_RCV_COMPLETION(target,pPacket,pEndpoint);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
|
||||
status));
|
||||
/* recyle this packet */
|
||||
HTC_RECYCLE_RX_PKT(target, pPacket);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
|
||||
}
|
||||
|
||||
/* synchronously wait for a control message from the target,
|
||||
* This function is used at initialization time ONLY. At init messages
|
||||
* on ENDPOINT 0 are expected. */
|
||||
A_STATUS HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT32 lookAhead;
|
||||
HTC_PACKET *pPacket = NULL;
|
||||
HTC_FRAME_HDR *pHdr;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
|
||||
|
||||
do {
|
||||
|
||||
*ppControlPacket = NULL;
|
||||
|
||||
/* call the polling function to see if we have a message */
|
||||
status = DevPollMboxMsgRecv(&target->Device,
|
||||
&lookAhead,
|
||||
HTC_TARGET_RESPONSE_TIMEOUT);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
|
||||
("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
|
||||
|
||||
/* check the lookahead */
|
||||
pHdr = (HTC_FRAME_HDR *)&lookAhead;
|
||||
|
||||
if (pHdr->EndpointID != ENDPOINT_0) {
|
||||
/* unexpected endpoint number, should be zero */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
/* bad message */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
pPacket = HTC_ALLOC_CONTROL_RX(target);
|
||||
|
||||
if (pPacket == NULL) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
pPacket->HTCReserved = lookAhead;
|
||||
pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
|
||||
|
||||
if (pPacket->ActualLength > pPacket->BufferLength) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we want synchronous operation */
|
||||
pPacket->Completion = NULL;
|
||||
|
||||
/* get the message from the device, this will block */
|
||||
status = HTCIssueRecv(target, pPacket);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process receive header */
|
||||
status = HTCProcessRecvHeader(target,pPacket,NULL);
|
||||
|
||||
pPacket->Status = status;
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
|
||||
status));
|
||||
break;
|
||||
}
|
||||
|
||||
/* give the caller this control message packet, they are responsible to free */
|
||||
*ppControlPacket = pPacket;
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
if (pPacket != NULL) {
|
||||
/* cleanup buffer on error */
|
||||
HTC_FREE_CONTROL_RX(target,pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* callback when device layer or lookahead report parsing detects a pending message */
|
||||
A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc)
|
||||
{
|
||||
HTC_TARGET *target = (HTC_TARGET *)Context;
|
||||
A_STATUS status = A_OK;
|
||||
HTC_PACKET *pPacket = NULL;
|
||||
HTC_FRAME_HDR *pHdr;
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
A_BOOL asyncProc = FALSE;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler LookAhead:0x%X \n",LookAhead));
|
||||
|
||||
if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
|
||||
/* We use async mode to get the packets if the device layer supports it.
|
||||
* The device layer interfaces with HIF in which HIF may have restrictions on
|
||||
* how interrupts are processed */
|
||||
asyncProc = TRUE;
|
||||
}
|
||||
|
||||
if (pAsyncProc != NULL) {
|
||||
/* indicate to caller how we decided to process this */
|
||||
*pAsyncProc = asyncProc;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
pHdr = (HTC_FRAME_HDR *)&LookAhead;
|
||||
|
||||
if (pHdr->EndpointID >= ENDPOINT_MAX) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
|
||||
/* invalid endpoint */
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
|
||||
pHdr->PayloadLen, HTC_MAX_PAYLOAD_LENGTH));
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
pEndpoint = &target->EndPoint[pHdr->EndpointID];
|
||||
|
||||
if (0 == pEndpoint->ServiceID) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
|
||||
/* endpoint isn't even connected */
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* lock RX to get a buffer */
|
||||
LOCK_HTC_RX(target);
|
||||
|
||||
/* get a packet from the endpoint recv queue */
|
||||
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
|
||||
|
||||
if (NULL == pPacket) {
|
||||
/* check for refill handler */
|
||||
if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
|
||||
UNLOCK_HTC_RX(target);
|
||||
/* call the re-fill handler */
|
||||
pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
|
||||
pHdr->EndpointID);
|
||||
LOCK_HTC_RX(target);
|
||||
/* check if we have more buffers */
|
||||
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
|
||||
/* fall through */
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == pPacket) {
|
||||
/* this is not an error, we simply need to mark that we are waiting for buffers.*/
|
||||
target->HTCStateFlags |= HTC_STATE_WAIT_BUFFERS;
|
||||
target->EpWaitingForBuffers = pHdr->EndpointID;
|
||||
status = A_NO_MEMORY;
|
||||
}
|
||||
|
||||
UNLOCK_HTC_RX(target);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
/* no buffers */
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_ASSERT(pPacket->Endpoint == pHdr->EndpointID);
|
||||
|
||||
/* make sure this message can fit in the endpoint buffer */
|
||||
if ((pHdr->PayloadLen + HTC_HDR_LENGTH) > pPacket->BufferLength) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("Payload Length Error : header reports payload of: %d, endpoint buffer size: %d \n",
|
||||
pHdr->PayloadLen, pPacket->BufferLength));
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
pPacket->HTCReserved = LookAhead; /* set expected look ahead */
|
||||
/* set the amount of data to fetch */
|
||||
pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
|
||||
|
||||
if (asyncProc) {
|
||||
/* we use async mode to get the packet if the device layer supports it
|
||||
* set our callback and context */
|
||||
pPacket->Completion = HTCRecvCompleteHandler;
|
||||
pPacket->pContext = target;
|
||||
} else {
|
||||
/* fully synchronous */
|
||||
pPacket->Completion = NULL;
|
||||
}
|
||||
|
||||
/* go fetch the packet */
|
||||
status = HTCIssueRecv(target, pPacket);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (asyncProc) {
|
||||
/* we did this asynchronously so we can get out of the loop, the asynch processing
|
||||
* creates a chain of requests to continue processing pending messages in the
|
||||
* context of callbacks */
|
||||
break;
|
||||
}
|
||||
|
||||
/* in the sync case, we process the packet, check lookaheads and then repeat */
|
||||
|
||||
LookAhead = 0;
|
||||
status = HTCProcessRecvHeader(target,pPacket,&LookAhead);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
HTC_RX_STAT_PROFILE(target,pEndpoint,LookAhead);
|
||||
DO_RCV_COMPLETION(target,pPacket,pEndpoint);
|
||||
|
||||
pPacket = NULL;
|
||||
|
||||
if (0 == LookAhead) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (A_NO_MEMORY == status) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" Endpoint :%d has no buffers, blocking receiver to prevent overrun.. \n",
|
||||
pHdr->EndpointID));
|
||||
/* try to stop receive at the device layer */
|
||||
DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
|
||||
status = A_OK;
|
||||
} else if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("Failed to get pending message : LookAhead Value: 0x%X (status = %d) \n",
|
||||
LookAhead, status));
|
||||
if (pPacket != NULL) {
|
||||
/* clean up packet on error */
|
||||
HTC_RECYCLE_RX_PKT(target, pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Makes a buffer available to the HTC module */
|
||||
A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
A_BOOL unblockRecv = FALSE;
|
||||
A_STATUS status = A_OK;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("+- HTCAddReceivePkt: endPointId: %d, buffer: 0x%X, length: %d\n",
|
||||
pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->BufferLength));
|
||||
|
||||
do {
|
||||
|
||||
if (HTC_STOPPING(target)) {
|
||||
status = A_ECANCELED;
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
|
||||
|
||||
pEndpoint = &target->EndPoint[pPacket->Endpoint];
|
||||
|
||||
LOCK_HTC_RX(target);
|
||||
|
||||
/* store receive packet */
|
||||
HTC_PACKET_ENQUEUE(&pEndpoint->RxBuffers, pPacket);
|
||||
|
||||
/* check if we are blocked waiting for a new buffer */
|
||||
if (target->HTCStateFlags & HTC_STATE_WAIT_BUFFERS) {
|
||||
if (target->EpWaitingForBuffers == pPacket->Endpoint) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
|
||||
target->EpWaitingForBuffers));
|
||||
target->HTCStateFlags &= ~HTC_STATE_WAIT_BUFFERS;
|
||||
target->EpWaitingForBuffers = ENDPOINT_MAX;
|
||||
unblockRecv = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_HTC_RX(target);
|
||||
|
||||
if (unblockRecv && !HTC_STOPPING(target)) {
|
||||
/* TODO : implement a buffer threshold count? */
|
||||
DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void HTCFlushEndpointRX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
|
||||
{
|
||||
HTC_PACKET *pPacket;
|
||||
|
||||
LOCK_HTC_RX(target);
|
||||
|
||||
while (1) {
|
||||
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
|
||||
if (NULL == pPacket) {
|
||||
break;
|
||||
}
|
||||
UNLOCK_HTC_RX(target);
|
||||
pPacket->Status = A_ECANCELED;
|
||||
pPacket->ActualLength = 0;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%X, length:%d, ep:%d \n",
|
||||
(A_UINT32)pPacket, pPacket->BufferLength, pPacket->Endpoint));
|
||||
/* give the packet back */
|
||||
pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext,
|
||||
pPacket);
|
||||
LOCK_HTC_RX(target);
|
||||
}
|
||||
|
||||
UNLOCK_HTC_RX(target);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void HTCFlushRecvBuffers(HTC_TARGET *target)
|
||||
{
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
int i;
|
||||
|
||||
/* NOTE: no need to flush endpoint 0, these buffers were
|
||||
* allocated as part of the HTC struct */
|
||||
for (i = ENDPOINT_1; i < ENDPOINT_MAX; i++) {
|
||||
pEndpoint = &target->EndPoint[i];
|
||||
if (pEndpoint->ServiceID == 0) {
|
||||
/* not in use.. */
|
||||
continue;
|
||||
}
|
||||
HTCFlushEndpointRX(target,pEndpoint);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "htc_internal.h"
|
||||
|
||||
#define DO_EP_TX_COMPLETION(ep,p) \
|
||||
{ \
|
||||
(p)->Completion = NULL; \
|
||||
(ep)->EpCallBacks.EpTxComplete((ep)->EpCallBacks.pContext,(p)); \
|
||||
}
|
||||
|
||||
|
||||
/* call the distribute credits callback with the distribution */
|
||||
#define DO_DISTRIBUTION(t,reason,description,pList) \
|
||||
{ \
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
|
||||
(" calling distribute function (%s) (dfn:0x%X, ctxt:0x%X, dist:0x%X) \n", \
|
||||
(description), \
|
||||
(A_UINT32)(t)->DistributeCredits, \
|
||||
(A_UINT32)(t)->pCredDistContext, \
|
||||
(A_UINT32)pList)); \
|
||||
(t)->DistributeCredits((t)->pCredDistContext, \
|
||||
(pList), \
|
||||
(reason)); \
|
||||
}
|
||||
|
||||
/* our internal send packet completion handler when packets are submited to the AR6K device
|
||||
* layer */
|
||||
static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
HTC_TARGET *target = (HTC_TARGET *)Context;
|
||||
HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint];
|
||||
|
||||
|
||||
if (A_FAILED(pPacket->Status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCSendPktCompletionHandler: request failed (status:%d, ep:%d) \n",
|
||||
pPacket->Status, pPacket->Endpoint));
|
||||
}
|
||||
/* first, fixup the head room we allocated */
|
||||
pPacket->pBuffer += HTC_HDR_LENGTH;
|
||||
/* do completion */
|
||||
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
||||
}
|
||||
|
||||
A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 SendFlags)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT8 *pHdrBuf;
|
||||
A_BOOL sync = FALSE;
|
||||
|
||||
/* caller always provides headrooom */
|
||||
pPacket->pBuffer -= HTC_HDR_LENGTH;
|
||||
pHdrBuf = pPacket->pBuffer;
|
||||
/* setup frame header */
|
||||
A_SET_UINT16_FIELD(pHdrBuf,HTC_FRAME_HDR,PayloadLen,(A_UINT16)pPacket->ActualLength);
|
||||
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,Flags,SendFlags);
|
||||
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,EndpointID, (A_UINT8)pPacket->Endpoint);
|
||||
|
||||
if (pPacket->Completion == NULL) {
|
||||
/* mark that this request was synchronously issued */
|
||||
sync = TRUE;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("+-HTCIssueSend: transmit length : %d (%s) \n",
|
||||
pPacket->ActualLength + HTC_HDR_LENGTH,
|
||||
sync ? "SYNC" : "ASYNC" ));
|
||||
|
||||
/* send message to device */
|
||||
status = DevSendPacket(&target->Device,
|
||||
pPacket,
|
||||
pPacket->ActualLength + HTC_HDR_LENGTH);
|
||||
|
||||
if (sync) {
|
||||
/* use local sync variable. If this was issued asynchronously, pPacket is no longer
|
||||
* safe to access. */
|
||||
pPacket->pBuffer += HTC_HDR_LENGTH;
|
||||
}
|
||||
|
||||
/* if this request was asynchronous, the packet completion routine will be invoked by
|
||||
* the device layer when the HIF layer completes the request */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* try to send the current packet or a packet at the head of the TX queue,
|
||||
* if there are no credits, the packet remains in the queue. */
|
||||
static void HTCTrySend(HTC_TARGET *target,
|
||||
HTC_PACKET *pPacketToSend,
|
||||
HTC_ENDPOINT_ID ep)
|
||||
{
|
||||
HTC_PACKET *pPacket;
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
int creditsRequired;
|
||||
A_UINT8 sendFlags;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (pPkt:0x%X)\n",(A_UINT32)pPacketToSend));
|
||||
|
||||
pEndpoint = &target->EndPoint[ep];
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
if (pPacketToSend != NULL) {
|
||||
/* caller supplied us a packet to queue to the tail of the HTC TX queue before
|
||||
* we check the tx queue */
|
||||
HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue,pPacketToSend);
|
||||
pEndpoint->CurrentTxQueueDepth++;
|
||||
}
|
||||
|
||||
/* now drain the TX queue for transmission as long as we have enough
|
||||
* credits */
|
||||
|
||||
while (1) {
|
||||
|
||||
if (HTC_QUEUE_EMPTY(&pEndpoint->TxQueue)) {
|
||||
/* nothing in the queue */
|
||||
break;
|
||||
}
|
||||
|
||||
sendFlags = 0;
|
||||
|
||||
/* get packet at head, but don't remove it */
|
||||
pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%X , Queue Depth: %d\n",
|
||||
(A_UINT32)pPacket, pEndpoint->CurrentTxQueueDepth));
|
||||
|
||||
/* figure out how many credits this message requires */
|
||||
creditsRequired = pPacket->ActualLength + HTC_HDR_LENGTH;
|
||||
creditsRequired += target->TargetCreditSize - 1;
|
||||
creditsRequired /= target->TargetCreditSize;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n",
|
||||
creditsRequired, pEndpoint->CreditDist.TxCredits));
|
||||
|
||||
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
|
||||
|
||||
/* not enough credits */
|
||||
|
||||
if (pPacket->Endpoint == ENDPOINT_0) {
|
||||
/* leave it in the queue */
|
||||
break;
|
||||
}
|
||||
/* invoke the registered distribution function only if this is not
|
||||
* endpoint 0, we let the driver layer provide more credits if it can.
|
||||
* We pass the credit distribution list starting at the endpoint in question
|
||||
* */
|
||||
|
||||
/* set how many credits we need */
|
||||
pEndpoint->CreditDist.TxCreditsSeek =
|
||||
creditsRequired - pEndpoint->CreditDist.TxCredits;
|
||||
DO_DISTRIBUTION(target,
|
||||
HTC_CREDIT_DIST_SEEK_CREDITS,
|
||||
"Seek Credits",
|
||||
&pEndpoint->CreditDist);
|
||||
|
||||
pEndpoint->CreditDist.TxCreditsSeek = 0;
|
||||
|
||||
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
|
||||
/* still not enough credits to send, leave packet in the queue */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
(" Not enough credits for ep %d leaving packet in queue..\n",
|
||||
pPacket->Endpoint));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pEndpoint->CreditDist.TxCredits -= creditsRequired;
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
|
||||
|
||||
/* check if we need credits */
|
||||
if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
|
||||
sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n"));
|
||||
}
|
||||
|
||||
/* now we can fully dequeue */
|
||||
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
|
||||
pEndpoint->CurrentTxQueueDepth--;
|
||||
|
||||
INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
|
||||
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
HTCIssueSend(target, pPacket, sendFlags);
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
/* go back and check for more messages */
|
||||
}
|
||||
|
||||
if (pEndpoint->CurrentTxQueueDepth >= pEndpoint->MaxTxQueueDepth) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n",
|
||||
ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth));
|
||||
UNLOCK_HTC_TX(target);
|
||||
/* queue is now full, let caller know */
|
||||
if (pEndpoint->EpCallBacks.EpSendFull != NULL) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n"));
|
||||
pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, ep);
|
||||
}
|
||||
} else {
|
||||
UNLOCK_HTC_TX(target);
|
||||
/* queue is now available for new packet, let caller know */
|
||||
if (pEndpoint->EpCallBacks.EpSendAvail)
|
||||
pEndpoint->EpCallBacks.EpSendAvail(pEndpoint->EpCallBacks.pContext, ep);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
|
||||
}
|
||||
|
||||
/* HTC API - HTCSendPkt */
|
||||
A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
HTC_ENDPOINT_ID ep;
|
||||
A_STATUS status = A_OK;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
||||
("+HTCSendPkt: Enter endPointId: %d, buffer: 0x%X, length: %d \n",
|
||||
pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->ActualLength));
|
||||
|
||||
ep = pPacket->Endpoint;
|
||||
AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
|
||||
pEndpoint = &target->EndPoint[ep];
|
||||
|
||||
do {
|
||||
|
||||
if (HTC_STOPPING(target)) {
|
||||
status = A_ECANCELED;
|
||||
pPacket->Status = status;
|
||||
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
||||
break;
|
||||
}
|
||||
/* everything sent through this interface is asynchronous */
|
||||
/* fill in HTC completion routines */
|
||||
pPacket->Completion = HTCSendPktCompletionHandler;
|
||||
pPacket->pContext = target;
|
||||
|
||||
HTCTrySend(target, pPacket, ep);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* check TX queues to drain because of credit distribution update */
|
||||
static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target)
|
||||
{
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
HTC_ENDPOINT_CREDIT_DIST *pDistItem;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
|
||||
pDistItem = target->EpCreditDistributionListHead;
|
||||
|
||||
/* run through the credit distribution list to see
|
||||
* if there are packets queued
|
||||
* NOTE: no locks need to be taken since the distribution list
|
||||
* is not dynamic (cannot be re-ordered) and we are not modifying any state */
|
||||
while (pDistItem != NULL) {
|
||||
pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved;
|
||||
|
||||
if (pEndpoint->CurrentTxQueueDepth > 0) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
|
||||
pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, pEndpoint->CurrentTxQueueDepth));
|
||||
/* try to start the stalled queue, this list is ordered by priority.
|
||||
* Highest priority queue get's processed first, if there are credits available the
|
||||
* highest priority queue will get a chance to reclaim credits from lower priority
|
||||
* ones */
|
||||
HTCTrySend(target, NULL, pDistItem->Endpoint);
|
||||
}
|
||||
|
||||
pDistItem = pDistItem->pNext;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
|
||||
}
|
||||
|
||||
/* process credit reports and call distribution function */
|
||||
void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
|
||||
{
|
||||
int i;
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
int totalCredits = 0;
|
||||
A_BOOL doDist = FALSE;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
|
||||
|
||||
/* lock out TX while we update credits */
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
for (i = 0; i < NumEntries; i++, pRpt++) {
|
||||
if (pRpt->EndpointID >= ENDPOINT_MAX) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
pEndpoint = &target->EndPoint[pRpt->EndpointID];
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n",
|
||||
pRpt->EndpointID, pRpt->Credits));
|
||||
|
||||
|
||||
#ifdef HTC_EP_STAT_PROFILING
|
||||
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
|
||||
|
||||
if (FromEndpoint == pRpt->EndpointID) {
|
||||
/* this credit report arrived on the same endpoint indicating it arrived in an RX
|
||||
* packet */
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
|
||||
} else if (FromEndpoint == ENDPOINT_0) {
|
||||
/* this credit arrived on endpoint 0 as a NULL message */
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
|
||||
} else {
|
||||
/* arrived on another endpoint */
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
|
||||
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (ENDPOINT_0 == pRpt->EndpointID) {
|
||||
/* always give endpoint 0 credits back */
|
||||
pEndpoint->CreditDist.TxCredits += pRpt->Credits;
|
||||
} else {
|
||||
/* for all other endpoints, update credits to distribute, the distribution function
|
||||
* will handle giving out credits back to the endpoints */
|
||||
pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
|
||||
/* flag that we have to do the distribution */
|
||||
doDist = TRUE;
|
||||
}
|
||||
|
||||
totalCredits += pRpt->Credits;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribute \n", totalCredits));
|
||||
|
||||
if (doDist) {
|
||||
/* this was a credit return based on a completed send operations
|
||||
* note, this is done with the lock held */
|
||||
DO_DISTRIBUTION(target,
|
||||
HTC_CREDIT_DIST_SEND_COMPLETE,
|
||||
"Send Complete",
|
||||
target->EpCreditDistributionListHead->pNext);
|
||||
}
|
||||
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
if (totalCredits) {
|
||||
HTCCheckEndpointTxQueues(target);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
|
||||
}
|
||||
|
||||
/* flush endpoint TX queue */
|
||||
static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_TX_TAG Tag)
|
||||
{
|
||||
HTC_PACKET *pPacket;
|
||||
HTC_PACKET_QUEUE discardQueue;
|
||||
|
||||
/* initialize the discard queue */
|
||||
INIT_HTC_PACKET_QUEUE(&discardQueue);
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
/* interate from the front of the TX queue and flush out packets */
|
||||
ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue, pPacket, HTC_PACKET, ListLink) {
|
||||
|
||||
/* check for removal */
|
||||
if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
|
||||
/* remove from queue */
|
||||
HTC_PACKET_REMOVE(pPacket);
|
||||
/* add it to the discard pile */
|
||||
HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
|
||||
pEndpoint->CurrentTxQueueDepth--;
|
||||
}
|
||||
|
||||
} ITERATE_END;
|
||||
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
/* empty the discard queue */
|
||||
while (1) {
|
||||
pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
|
||||
if (NULL == pPacket) {
|
||||
break;
|
||||
}
|
||||
pPacket->Status = A_ECANCELED;
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%X, length:%d, ep:%d tag:0x%X \n",
|
||||
(A_UINT32)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
|
||||
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *)pEPDist->pHTCReserved;
|
||||
#endif
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X --------------\n",
|
||||
pEPDist->Endpoint, pEPDist->ServiceID));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%X next:0x%X prev:0x%X\n",
|
||||
(A_UINT32)pEPDist, (A_UINT32)pEPDist->pNext, (A_UINT32)pEPDist->pPrev));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->DistFlags));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCreditsNorm));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCreditsMin));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCredits));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCreditsAssigned));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCreditsSeek));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCreditSize));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCreditsToDist));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n", pEndpoint->CurrentTxQueueDepth));
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
|
||||
}
|
||||
|
||||
void DumpCreditDistStates(HTC_TARGET *target)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead;
|
||||
|
||||
while (pEPList != NULL) {
|
||||
DumpCreditDist(pEPList);
|
||||
pEPList = pEPList->pNext;
|
||||
}
|
||||
|
||||
if (target->DistributeCredits != NULL) {
|
||||
DO_DISTRIBUTION(target,
|
||||
HTC_DUMP_CREDIT_STATE,
|
||||
"Dump State",
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* flush all send packets from all endpoint queues */
|
||||
void HTCFlushSendPkts(HTC_TARGET *target)
|
||||
{
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
int i;
|
||||
|
||||
DumpCreditDistStates(target);
|
||||
|
||||
for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
|
||||
pEndpoint = &target->EndPoint[i];
|
||||
if (pEndpoint->ServiceID == 0) {
|
||||
/* not in use.. */
|
||||
continue;
|
||||
}
|
||||
HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* HTC API to flush an endpoint's TX queue*/
|
||||
void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
|
||||
|
||||
if (pEndpoint->ServiceID == 0) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
/* not in use.. */
|
||||
return;
|
||||
}
|
||||
|
||||
HTCFlushEndpointTX(target, pEndpoint, Tag);
|
||||
}
|
||||
|
||||
/* HTC API to indicate activity to the credit distribution function */
|
||||
void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
|
||||
HTC_ENDPOINT_ID Endpoint,
|
||||
A_BOOL Active)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
|
||||
A_BOOL doDist = FALSE;
|
||||
|
||||
if (pEndpoint->ServiceID == 0) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
/* not in use.. */
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK_HTC_TX(target);
|
||||
|
||||
if (Active) {
|
||||
if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
|
||||
/* mark active now */
|
||||
pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
|
||||
doDist = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
|
||||
/* mark inactive now */
|
||||
pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
|
||||
doDist = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDist) {
|
||||
/* do distribution again based on activity change
|
||||
* note, this is done with the lock held */
|
||||
DO_DISTRIBUTION(target,
|
||||
HTC_CREDIT_DIST_ACTIVITY_CHANGE,
|
||||
"Activity Change",
|
||||
target->EpCreditDistributionListHead->pNext);
|
||||
}
|
||||
|
||||
UNLOCK_HTC_TX(target);
|
||||
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "htc_internal.h"
|
||||
|
||||
void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
/* not implemented
|
||||
* we do not send control TX frames during normal runtime, only during setup */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* callback when a control message arrives on this endpoint */
|
||||
void HTCControlRecv(void *Context, HTC_PACKET *pPacket)
|
||||
{
|
||||
AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0);
|
||||
|
||||
/* the only control messages we are expecting are NULL messages (credit resports), which should
|
||||
* never get here */
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
("HTCControlRecv, got message with length:%d \n",
|
||||
pPacket->ActualLength + HTC_HDR_LENGTH));
|
||||
|
||||
/* dump header and message */
|
||||
DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH,
|
||||
pPacket->ActualLength + HTC_HDR_LENGTH,
|
||||
"Unexpected ENDPOINT 0 Message");
|
||||
|
||||
HTC_RECYCLE_RX_PKT((HTC_TARGET*)Context,pPacket);
|
||||
}
|
||||
|
||||
A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
|
||||
{
|
||||
HTC_PACKET *pSendPacket = NULL;
|
||||
A_STATUS status;
|
||||
HTC_SETUP_COMPLETE_MSG *pSetupComplete;
|
||||
|
||||
do {
|
||||
/* allocate a packet to send to the target */
|
||||
pSendPacket = HTC_ALLOC_CONTROL_TX(target);
|
||||
|
||||
if (NULL == pSendPacket) {
|
||||
status = A_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* assemble setup complete message */
|
||||
pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
|
||||
A_MEMZERO(pSetupComplete,sizeof(HTC_SETUP_COMPLETE_MSG));
|
||||
pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;
|
||||
|
||||
SET_HTC_PACKET_INFO_TX(pSendPacket,
|
||||
NULL,
|
||||
(A_UINT8 *)pSetupComplete,
|
||||
sizeof(HTC_SETUP_COMPLETE_MSG),
|
||||
ENDPOINT_0,
|
||||
HTC_SERVICE_TX_PACKET_TAG);
|
||||
|
||||
/* we want synchronous operation */
|
||||
pSendPacket->Completion = NULL;
|
||||
/* send the message */
|
||||
status = HTCIssueSend(target,pSendPacket,0);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (pSendPacket != NULL) {
|
||||
HTC_FREE_CONTROL_TX(target,pSendPacket);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
|
||||
HTC_SERVICE_CONNECT_REQ *pConnectReq,
|
||||
HTC_SERVICE_CONNECT_RESP *pConnectResp)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
A_STATUS status = A_OK;
|
||||
HTC_PACKET *pRecvPacket = NULL;
|
||||
HTC_PACKET *pSendPacket = NULL;
|
||||
HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
|
||||
HTC_CONNECT_SERVICE_MSG *pConnectMsg;
|
||||
HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
|
||||
HTC_ENDPOINT *pEndpoint;
|
||||
int maxMsgSize = 0;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
|
||||
(A_UINT32)target, pConnectReq->ServiceID));
|
||||
|
||||
do {
|
||||
|
||||
AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
|
||||
|
||||
if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
|
||||
/* special case for pseudo control service */
|
||||
assignedEndpoint = ENDPOINT_0;
|
||||
maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
|
||||
} else {
|
||||
/* allocate a packet to send to the target */
|
||||
pSendPacket = HTC_ALLOC_CONTROL_TX(target);
|
||||
|
||||
if (NULL == pSendPacket) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
/* assemble connect service message */
|
||||
pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer;
|
||||
AR_DEBUG_ASSERT(pConnectMsg != NULL);
|
||||
A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG));
|
||||
pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID;
|
||||
pConnectMsg->ServiceID = pConnectReq->ServiceID;
|
||||
pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags;
|
||||
/* check caller if it wants to transfer meta data */
|
||||
if ((pConnectReq->pMetaData != NULL) &&
|
||||
(pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
|
||||
/* copy meta data into message buffer (after header ) */
|
||||
A_MEMCPY((A_UINT8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG),
|
||||
pConnectReq->pMetaData,
|
||||
pConnectReq->MetaDataLength);
|
||||
pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength;
|
||||
}
|
||||
|
||||
SET_HTC_PACKET_INFO_TX(pSendPacket,
|
||||
NULL,
|
||||
(A_UINT8 *)pConnectMsg,
|
||||
sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
|
||||
ENDPOINT_0,
|
||||
HTC_SERVICE_TX_PACKET_TAG);
|
||||
|
||||
/* we want synchronous operation */
|
||||
pSendPacket->Completion = NULL;
|
||||
|
||||
status = HTCIssueSend(target,pSendPacket,0);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* wait for response */
|
||||
status = HTCWaitforControlMessage(target, &pRecvPacket);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
/* we controlled the buffer creation so it has to be properly aligned */
|
||||
pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;
|
||||
|
||||
if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) ||
|
||||
(pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
|
||||
/* this message is not valid */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
pConnectResp->ConnectRespCode = pResponseMsg->Status;
|
||||
/* check response status */
|
||||
if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
||||
(" Target failed service 0x%X connect request (status:%d)\n",
|
||||
pResponseMsg->ServiceID, pResponseMsg->Status));
|
||||
status = A_EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
assignedEndpoint = pResponseMsg->EndpointID;
|
||||
maxMsgSize = pResponseMsg->MaxMsgSize;
|
||||
|
||||
if ((pConnectResp->pMetaData != NULL) &&
|
||||
(pResponseMsg->ServiceMetaLength > 0) &&
|
||||
(pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
|
||||
/* caller supplied a buffer and the target responded with data */
|
||||
int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength);
|
||||
/* copy the meta data */
|
||||
A_MEMCPY(pConnectResp->pMetaData,
|
||||
((A_UINT8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG),
|
||||
copyLength);
|
||||
pConnectResp->ActualLength = copyLength;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* the rest of these are parameter checks so set the error status */
|
||||
status = A_EPROTO;
|
||||
|
||||
if (assignedEndpoint >= ENDPOINT_MAX) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 == maxMsgSize) {
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
pEndpoint = &target->EndPoint[assignedEndpoint];
|
||||
|
||||
if (pEndpoint->ServiceID != 0) {
|
||||
/* endpoint already in use! */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* return assigned endpoint to caller */
|
||||
pConnectResp->Endpoint = assignedEndpoint;
|
||||
pConnectResp->MaxMsgLength = maxMsgSize;
|
||||
|
||||
/* setup the endpoint */
|
||||
pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
|
||||
pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
|
||||
pEndpoint->MaxMsgLength = maxMsgSize;
|
||||
/* copy all the callbacks */
|
||||
pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
|
||||
INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers);
|
||||
INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
|
||||
/* set the credit distribution info for this endpoint, this information is
|
||||
* passed back to the credit distribution callback function */
|
||||
pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID;
|
||||
pEndpoint->CreditDist.pHTCReserved = pEndpoint;
|
||||
pEndpoint->CreditDist.Endpoint = assignedEndpoint;
|
||||
pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize;
|
||||
pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize;
|
||||
|
||||
if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
|
||||
pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
|
||||
}
|
||||
|
||||
status = A_OK;
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (pSendPacket != NULL) {
|
||||
HTC_FREE_CONTROL_TX(target,pSendPacket);
|
||||
}
|
||||
|
||||
if (pRecvPacket != NULL) {
|
||||
HTC_FREE_CONTROL_RX(target,pRecvPacket);
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void AddToEndpointDistList(HTC_TARGET *target, HTC_ENDPOINT_CREDIT_DIST *pEpDist)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEntry,*pLastEntry;
|
||||
|
||||
if (NULL == target->EpCreditDistributionListHead) {
|
||||
target->EpCreditDistributionListHead = pEpDist;
|
||||
pEpDist->pNext = NULL;
|
||||
pEpDist->pPrev = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* queue to the end of the list, this does not have to be very
|
||||
* fast since this list is built at startup time */
|
||||
pCurEntry = target->EpCreditDistributionListHead;
|
||||
|
||||
while (pCurEntry) {
|
||||
pLastEntry = pCurEntry;
|
||||
pCurEntry = pCurEntry->pNext;
|
||||
}
|
||||
|
||||
pLastEntry->pNext = pEpDist;
|
||||
pEpDist->pPrev = pLastEntry;
|
||||
pEpDist->pNext = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* default credit init callback */
|
||||
static void HTCDefaultCreditInit(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPList,
|
||||
int TotalCredits)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
|
||||
int totalEps = 0;
|
||||
int creditsPerEndpoint;
|
||||
|
||||
pCurEpDist = pEPList;
|
||||
/* first run through the list and figure out how many endpoints we are dealing with */
|
||||
while (pCurEpDist != NULL) {
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
totalEps++;
|
||||
}
|
||||
|
||||
/* even distribution */
|
||||
creditsPerEndpoint = TotalCredits/totalEps;
|
||||
|
||||
pCurEpDist = pEPList;
|
||||
/* run through the list and set minimum and normal credits and
|
||||
* provide the endpoint with some credits to start */
|
||||
while (pCurEpDist != NULL) {
|
||||
|
||||
if (creditsPerEndpoint < pCurEpDist->TxCreditsPerMaxMsg) {
|
||||
/* too many endpoints and not enough credits */
|
||||
AR_DEBUG_ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
/* our minimum is set for at least 1 max message */
|
||||
pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
|
||||
/* this value is ignored by our credit alg, since we do
|
||||
* not dynamically adjust credits, this is the policy of
|
||||
* the "default" credit distribution, something simple and easy */
|
||||
pCurEpDist->TxCreditsNorm = 0xFFFF;
|
||||
/* give the endpoint minimum credits */
|
||||
pCurEpDist->TxCredits = creditsPerEndpoint;
|
||||
pCurEpDist->TxCreditsAssigned = creditsPerEndpoint;
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* default credit distribution callback, NOTE, this callback holds the TX lock */
|
||||
void HTCDefaultCreditDist(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
|
||||
HTC_CREDIT_DIST_REASON Reason)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
|
||||
|
||||
if (Reason == HTC_CREDIT_DIST_SEND_COMPLETE) {
|
||||
pCurEpDist = pEPDistList;
|
||||
/* simple distribution */
|
||||
while (pCurEpDist != NULL) {
|
||||
if (pCurEpDist->TxCreditsToDist > 0) {
|
||||
/* just give the endpoint back the credits */
|
||||
pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
|
||||
pCurEpDist->TxCreditsToDist = 0;
|
||||
}
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
/* note we do not need to handle the other reason codes as this is a very
|
||||
* simple distribution scheme, no need to seek for more credits or handle inactivity */
|
||||
}
|
||||
|
||||
void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
|
||||
void *pCreditDistContext,
|
||||
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
|
||||
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
|
||||
HTC_SERVICE_ID ServicePriorityOrder[],
|
||||
int ListLength)
|
||||
{
|
||||
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
||||
int i;
|
||||
int ep;
|
||||
|
||||
if (CreditInitFunc != NULL) {
|
||||
/* caller has supplied their own distribution functions */
|
||||
target->InitCredits = CreditInitFunc;
|
||||
AR_DEBUG_ASSERT(CreditDistFunc != NULL);
|
||||
target->DistributeCredits = CreditDistFunc;
|
||||
target->pCredDistContext = pCreditDistContext;
|
||||
} else {
|
||||
/* caller wants HTC to do distribution */
|
||||
/* if caller wants service to handle distributions then
|
||||
* it must set both of these to NULL! */
|
||||
AR_DEBUG_ASSERT(CreditDistFunc == NULL);
|
||||
target->InitCredits = HTCDefaultCreditInit;
|
||||
target->DistributeCredits = HTCDefaultCreditDist;
|
||||
target->pCredDistContext = target;
|
||||
}
|
||||
|
||||
/* always add HTC control endpoint first, we only expose the list after the
|
||||
* first one, this is added for TX queue checking */
|
||||
AddToEndpointDistList(target, &target->EndPoint[ENDPOINT_0].CreditDist);
|
||||
|
||||
/* build the list of credit distribution structures in priority order
|
||||
* supplied by the caller, these will follow endpoint 0 */
|
||||
for (i = 0; i < ListLength; i++) {
|
||||
/* match services with endpoints and add the endpoints to the distribution list
|
||||
* in FIFO order */
|
||||
for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
|
||||
if (target->EndPoint[ep].ServiceID == ServicePriorityOrder[i]) {
|
||||
/* queue this one to the list */
|
||||
AddToEndpointDistList(target, &target->EndPoint[ep].CreditDist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AR6000_REGDUMP_H__
|
||||
#define __AR6000_REGDUMP_H__
|
||||
|
||||
#if !defined(__ASSEMBLER__)
|
||||
/*
|
||||
* Target CPU state at the time of failure is reflected
|
||||
* in a register dump, which the Host can fetch through
|
||||
* the diagnostic window.
|
||||
*/
|
||||
|
||||
struct MIPS_exception_frame_s {
|
||||
A_UINT32 pc; /* Program Counter */
|
||||
A_UINT32 at; /* MIPS General Purpose registers */
|
||||
A_UINT32 v0;
|
||||
A_UINT32 v1;
|
||||
A_UINT32 a0;
|
||||
A_UINT32 a1;
|
||||
A_UINT32 a2;
|
||||
A_UINT32 a3;
|
||||
A_UINT32 t0;
|
||||
A_UINT32 t1;
|
||||
A_UINT32 t2;
|
||||
A_UINT32 t3;
|
||||
A_UINT32 t4;
|
||||
A_UINT32 t5;
|
||||
A_UINT32 t6;
|
||||
A_UINT32 t7;
|
||||
A_UINT32 s0;
|
||||
A_UINT32 s1;
|
||||
A_UINT32 s2;
|
||||
A_UINT32 s3;
|
||||
A_UINT32 s4;
|
||||
A_UINT32 s5;
|
||||
A_UINT32 s6;
|
||||
A_UINT32 s7;
|
||||
A_UINT32 t8;
|
||||
A_UINT32 t9;
|
||||
A_UINT32 k0;
|
||||
A_UINT32 k1;
|
||||
A_UINT32 gp;
|
||||
A_UINT32 sp;
|
||||
A_UINT32 s8;
|
||||
A_UINT32 ra;
|
||||
A_UINT32 cause; /* Selected coprocessor regs */
|
||||
A_UINT32 status;
|
||||
};
|
||||
typedef struct MIPS_exception_frame_s CPU_exception_frame_t;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Offsets into MIPS_exception_frame structure, for use in assembler code
|
||||
* MUST MATCH C STRUCTURE ABOVE
|
||||
*/
|
||||
#define RD_pc 0
|
||||
#define RD_at 1
|
||||
#define RD_v0 2
|
||||
#define RD_v1 3
|
||||
#define RD_a0 4
|
||||
#define RD_a1 5
|
||||
#define RD_a2 6
|
||||
#define RD_a3 7
|
||||
#define RD_t0 8
|
||||
#define RD_t1 9
|
||||
#define RD_t2 10
|
||||
#define RD_t3 11
|
||||
#define RD_t4 12
|
||||
#define RD_t5 13
|
||||
#define RD_t6 14
|
||||
#define RD_t7 15
|
||||
#define RD_s0 16
|
||||
#define RD_s1 17
|
||||
#define RD_s2 18
|
||||
#define RD_s3 19
|
||||
#define RD_s4 20
|
||||
#define RD_s5 21
|
||||
#define RD_s6 22
|
||||
#define RD_s7 23
|
||||
#define RD_t8 24
|
||||
#define RD_t9 25
|
||||
#define RD_k0 26
|
||||
#define RD_k1 27
|
||||
#define RD_gp 28
|
||||
#define RD_sp 29
|
||||
#define RD_s8 30
|
||||
#define RD_ra 31
|
||||
#define RD_cause 32
|
||||
#define RD_status 33
|
||||
|
||||
#define RD_SIZE (34*4) /* Space for this number of words */
|
||||
|
||||
#endif /* __AR6000_REGDUMP_H__ */
|
|
@ -0,0 +1,36 @@
|
|||
#define __VER_MAJOR_ 2
|
||||
#define __VER_MINOR_ 0
|
||||
#define __VER_PATCH_ 0
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* The makear6ksdk script (used for release builds) modifies the following line.
|
||||
*/
|
||||
#define __BUILD_NUMBER_ 18
|
||||
|
||||
|
||||
/* Format of the version number. */
|
||||
#define VER_MAJOR_BIT_OFFSET 28
|
||||
#define VER_MINOR_BIT_OFFSET 24
|
||||
#define VER_PATCH_BIT_OFFSET 16
|
||||
#define VER_BUILD_NUM_BIT_OFFSET 0
|
||||
|
||||
|
||||
/*
|
||||
* The version has the following format:
|
||||
* Bits 28-31: Major version
|
||||
* Bits 24-27: Minor version
|
||||
* Bits 16-23: Patch version
|
||||
* Bits 0-15: Build number (automatically generated during build process )
|
||||
* E.g. Build 1.1.3.7 would be represented as 0x11030007.
|
||||
*
|
||||
* DO NOT split the following macro into multiple lines as this may confuse the build scripts.
|
||||
*/
|
||||
#define AR6K_SW_VERSION ( ( __VER_MAJOR_ << VER_MAJOR_BIT_OFFSET ) + ( __VER_MINOR_ << VER_MINOR_BIT_OFFSET ) + ( __VER_PATCH_ << VER_PATCH_BIT_OFFSET ) + ( __BUILD_NUMBER_ << VER_BUILD_NUM_BIT_OFFSET ) )
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#define __VER_MAJOR_ 2
|
||||
#define __VER_MINOR_ 0
|
||||
#define __VER_PATCH_ 0
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* The makear6ksdk script (used for release builds) modifies the following line.
|
||||
*/
|
||||
#define __BUILD_NUMBER_ 18
|
||||
|
||||
|
||||
/* Format of the version number. */
|
||||
#define VER_MAJOR_BIT_OFFSET 28
|
||||
#define VER_MINOR_BIT_OFFSET 24
|
||||
#define VER_PATCH_BIT_OFFSET 16
|
||||
#define VER_BUILD_NUM_BIT_OFFSET 0
|
||||
|
||||
|
||||
/*
|
||||
* The version has the following format:
|
||||
* Bits 28-31: Major version
|
||||
* Bits 24-27: Minor version
|
||||
* Bits 16-23: Patch version
|
||||
* Bits 0-15: Build number (automatically generated during build process )
|
||||
* E.g. Build 1.1.3.7 would be represented as 0x11030007.
|
||||
*
|
||||
* DO NOT split the following macro into multiple lines as this may confuse the build scripts.
|
||||
*/
|
||||
#define AR6K_SW_VERSION ( ( __VER_MAJOR_ << VER_MAJOR_BIT_OFFSET ) + ( __VER_MINOR_ << VER_MINOR_BIT_OFFSET ) + ( __VER_PATCH_ << VER_PATCH_BIT_OFFSET ) + ( __BUILD_NUMBER_ << VER_BUILD_NUM_BIT_OFFSET ) )
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This file contains the definitions for AR6001 registers
|
||||
* that may be directly manipulated by Host software.
|
||||
*/
|
||||
|
||||
#ifndef __AR6KHWREG_H__
|
||||
#define __AR6KHWREG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Host registers */
|
||||
#define HOST_INT_STATUS_ADDRESS 0x00000400
|
||||
#define CPU_INT_STATUS_ADDRESS 0x00000401
|
||||
#define ERROR_INT_STATUS_ADDRESS 0x00000402
|
||||
#define INT_STATUS_ENABLE_ADDRESS 0x00000418
|
||||
#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
|
||||
#define COUNT_ADDRESS 0x00000420
|
||||
#define COUNT_DEC_ADDRESS 0x00000440
|
||||
#define WINDOW_DATA_ADDRESS 0x00000474
|
||||
#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
|
||||
#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
|
||||
|
||||
/* Target addresses */
|
||||
#define RESET_CONTROL_ADDRESS 0x0c000000
|
||||
#define MC_REMAP_VALID_ADDRESS 0x0c004080
|
||||
#define MC_REMAP_SIZE_ADDRESS 0x0c004100
|
||||
#define MC_REMAP_COMPARE_ADDRESS 0x0c004180
|
||||
#define MC_REMAP_TARGET_ADDRESS 0x0c004200
|
||||
#define LOCAL_COUNT_ADDRESS 0x0c014080
|
||||
#define LOCAL_SCRATCH_ADDRESS 0x0c0140c0
|
||||
|
||||
|
||||
#define INT_STATUS_ENABLE_ERROR_MSB 7
|
||||
#define INT_STATUS_ENABLE_ERROR_LSB 7
|
||||
#define INT_STATUS_ENABLE_ERROR_MASK 0x00000080
|
||||
#define INT_STATUS_ENABLE_ERROR_GET(x) (((x) & INT_STATUS_ENABLE_ERROR_MASK) >> INT_STATUS_ENABLE_ERROR_LSB)
|
||||
#define INT_STATUS_ENABLE_ERROR_SET(x) (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK)
|
||||
|
||||
#define INT_STATUS_ENABLE_CPU_MSB 6
|
||||
#define INT_STATUS_ENABLE_CPU_LSB 6
|
||||
#define INT_STATUS_ENABLE_CPU_MASK 0x00000040
|
||||
#define INT_STATUS_ENABLE_CPU_GET(x) (((x) & INT_STATUS_ENABLE_CPU_MASK) >> INT_STATUS_ENABLE_CPU_LSB)
|
||||
#define INT_STATUS_ENABLE_CPU_SET(x) (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK)
|
||||
|
||||
#define INT_STATUS_ENABLE_COUNTER_MSB 4
|
||||
#define INT_STATUS_ENABLE_COUNTER_LSB 4
|
||||
#define INT_STATUS_ENABLE_COUNTER_MASK 0x00000010
|
||||
#define INT_STATUS_ENABLE_COUNTER_GET(x) (((x) & INT_STATUS_ENABLE_COUNTER_MASK) >> INT_STATUS_ENABLE_COUNTER_LSB)
|
||||
#define INT_STATUS_ENABLE_COUNTER_SET(x) (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & INT_STATUS_ENABLE_COUNTER_MASK)
|
||||
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_MSB 3
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_LSB 0
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_GET(x) (((x) & INT_STATUS_ENABLE_MBOX_DATA_MASK) >> INT_STATUS_ENABLE_MBOX_DATA_LSB)
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & INT_STATUS_ENABLE_MBOX_DATA_MASK)
|
||||
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MSB 1
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) >> ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB)
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK)
|
||||
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MSB 0
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) >> ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB)
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK)
|
||||
|
||||
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_MSB 7
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_LSB 0
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_GET(x) (((x) & CPU_INT_STATUS_ENABLE_BIT_MASK) >> CPU_INT_STATUS_ENABLE_BIT_LSB)
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_SET(x) (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & CPU_INT_STATUS_ENABLE_BIT_MASK)
|
||||
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_MSB 7
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_LSB 0
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_GET(x) (((x) & COUNTER_INT_STATUS_ENABLE_BIT_MASK) >> COUNTER_INT_STATUS_ENABLE_BIT_LSB)
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & COUNTER_INT_STATUS_ENABLE_BIT_MASK)
|
||||
|
||||
#define ERROR_INT_STATUS_WAKEUP_MSB 2
|
||||
#define ERROR_INT_STATUS_WAKEUP_LSB 2
|
||||
#define ERROR_INT_STATUS_WAKEUP_MASK 0x00000004
|
||||
#define ERROR_INT_STATUS_WAKEUP_GET(x) (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> ERROR_INT_STATUS_WAKEUP_LSB)
|
||||
#define ERROR_INT_STATUS_WAKEUP_SET(x) (((x) << ERROR_INT_STATUS_WAKEUP_LSB) & ERROR_INT_STATUS_WAKEUP_MASK)
|
||||
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_MSB 1
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> ERROR_INT_STATUS_RX_UNDERFLOW_LSB)
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_SET(x) (((x) << ERROR_INT_STATUS_RX_UNDERFLOW_LSB) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK)
|
||||
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_MSB 0
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_LSB 0
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> ERROR_INT_STATUS_TX_OVERFLOW_LSB)
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_SET(x) (((x) << ERROR_INT_STATUS_TX_OVERFLOW_LSB) & ERROR_INT_STATUS_TX_OVERFLOW_MASK)
|
||||
|
||||
#define HOST_INT_STATUS_ERROR_MSB 7
|
||||
#define HOST_INT_STATUS_ERROR_LSB 7
|
||||
#define HOST_INT_STATUS_ERROR_MASK 0x00000080
|
||||
#define HOST_INT_STATUS_ERROR_GET(x) (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB)
|
||||
#define HOST_INT_STATUS_ERROR_SET(x) (((x) << HOST_INT_STATUS_ERROR_LSB) & HOST_INT_STATUS_ERROR_MASK)
|
||||
|
||||
#define HOST_INT_STATUS_CPU_MSB 6
|
||||
#define HOST_INT_STATUS_CPU_LSB 6
|
||||
#define HOST_INT_STATUS_CPU_MASK 0x00000040
|
||||
#define HOST_INT_STATUS_CPU_GET(x) (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB)
|
||||
#define HOST_INT_STATUS_CPU_SET(x) (((x) << HOST_INT_STATUS_CPU_LSB) & HOST_INT_STATUS_CPU_MASK)
|
||||
|
||||
#define HOST_INT_STATUS_COUNTER_MSB 4
|
||||
#define HOST_INT_STATUS_COUNTER_LSB 4
|
||||
#define HOST_INT_STATUS_COUNTER_MASK 0x00000010
|
||||
#define HOST_INT_STATUS_COUNTER_GET(x) (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB)
|
||||
#define HOST_INT_STATUS_COUNTER_SET(x) (((x) << HOST_INT_STATUS_COUNTER_LSB) & HOST_INT_STATUS_COUNTER_MASK)
|
||||
|
||||
#define RESET_CONTROL_WARM_RST_MSB 7
|
||||
#define RESET_CONTROL_WARM_RST_LSB 7
|
||||
#define RESET_CONTROL_WARM_RST_MASK 0x00000080
|
||||
#define RESET_CONTROL_WARM_RST_GET(x) (((x) & RESET_CONTROL_WARM_RST_MASK) >> RESET_CONTROL_WARM_RST_LSB)
|
||||
#define RESET_CONTROL_WARM_RST_SET(x) (((x) << RESET_CONTROL_WARM_RST_LSB) & RESET_CONTROL_WARM_RST_MASK)
|
||||
|
||||
#define RESET_CONTROL_COLD_RST_MSB 8
|
||||
#define RESET_CONTROL_COLD_RST_LSB 8
|
||||
#define RESET_CONTROL_COLD_RST_MASK 0x00000100
|
||||
#define RESET_CONTROL_COLD_RST_GET(x) (((x) & RESET_CONTROL_COLD_RST_MASK) >> RESET_CONTROL_COLD_RST_LSB)
|
||||
#define RESET_CONTROL_COLD_RST_SET(x) (((x) << RESET_CONTROL_COLD_RST_LSB) & RESET_CONTROL_COLD_RST_MASK)
|
||||
|
||||
#define RESET_CAUSE_LAST_MSB 2
|
||||
#define RESET_CAUSE_LAST_LSB 0
|
||||
#define RESET_CAUSE_LAST_MASK 0x00000007
|
||||
#define RESET_CAUSE_LAST_GET(x) (((x) & RESET_CAUSE_LAST_MASK) >> RESET_CAUSE_LAST_LSB)
|
||||
#define RESET_CAUSE_LAST_SET(x) (((x) << RESET_CAUSE_LAST_LSB) & RESET_CAUSE_LAST_MASK)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AR6KHWREG_H__ */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _A_CONFIG_H_
|
||||
#define _A_CONFIG_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains software configuration options that enables
|
||||
* specific software "features"
|
||||
*/
|
||||
#include "../ar6000/config_linux.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef _A_DEBUG_H_
|
||||
#define _A_DEBUG_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <a_types.h>
|
||||
#include <a_osapi.h>
|
||||
|
||||
#define DBG_INFO 0x00000001
|
||||
#define DBG_ERROR 0x00000002
|
||||
#define DBG_WARNING 0x00000004
|
||||
#define DBG_SDIO 0x00000008
|
||||
#define DBG_HIF 0x00000010
|
||||
#define DBG_HTC 0x00000020
|
||||
#define DBG_WMI 0x00000040
|
||||
#define DBG_WMI2 0x00000080
|
||||
#define DBG_DRIVER 0x00000100
|
||||
|
||||
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
|
||||
|
||||
#include "../ar6000/debug_linux.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _A_DRV_H_
|
||||
#define _A_DRV_H_
|
||||
/*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_drv.h#1 $
|
||||
*
|
||||
* This file contains the definitions of the basic atheros data types.
|
||||
* It is used to map the data types in atheros files to a platform specific
|
||||
* type.
|
||||
*
|
||||
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ar6000/athdrv_linux.h"
|
||||
|
||||
#endif /* _ADRV_H_ */
|
|
@ -0,0 +1,185 @@
|
|||
#ifndef _A_DRV_API_H_
|
||||
#define _A_DRV_API_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/** **/
|
||||
/** WMI related hooks **/
|
||||
/** **/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#include <ar6000_api.h>
|
||||
|
||||
#define A_WMI_CHANNELLIST_RX(devt, numChan, chanList) \
|
||||
ar6000_channelList_rx((devt), (numChan), (chanList))
|
||||
|
||||
#define A_WMI_SET_NUMDATAENDPTS(devt, num) \
|
||||
ar6000_set_numdataendpts((devt), (num))
|
||||
|
||||
#define A_WMI_CONTROL_TX(devt, osbuf, streamID) \
|
||||
ar6000_control_tx((devt), (osbuf), (streamID))
|
||||
|
||||
#define A_WMI_TARGETSTATS_EVENT(devt, pStats) \
|
||||
ar6000_targetStats_event((devt), (pStats))
|
||||
|
||||
#define A_WMI_SCANCOMPLETE_EVENT(devt, status) \
|
||||
ar6000_scanComplete_event((devt), (status))
|
||||
|
||||
#ifdef CONFIG_HOST_DSET_SUPPORT
|
||||
|
||||
#define A_WMI_DSET_DATA_REQ(devt, access_cookie, offset, length, targ_buf, targ_reply_fn, targ_reply_arg) \
|
||||
ar6000_dset_data_req((devt), (access_cookie), (offset), (length), (targ_buf), (targ_reply_fn), (targ_reply_arg))
|
||||
|
||||
#define A_WMI_DSET_CLOSE(devt, access_cookie) \
|
||||
ar6000_dset_close((devt), (access_cookie))
|
||||
|
||||
#endif
|
||||
|
||||
#define A_WMI_DSET_OPEN_REQ(devt, id, targ_handle, targ_reply_fn, targ_reply_arg) \
|
||||
ar6000_dset_open_req((devt), (id), (targ_handle), (targ_reply_fn), (targ_reply_arg))
|
||||
|
||||
#define A_WMI_CONNECT_EVENT(devt, channel, bssid, listenInterval, beaconInterval, networkType, beaconIeLen, assocReqLen, assocRespLen, assocInfo) \
|
||||
ar6000_connect_event((devt), (channel), (bssid), (listenInterval), (beaconInterval), (networkType), (beaconIeLen), (assocReqLen), (assocRespLen), (assocInfo))
|
||||
|
||||
#define A_WMI_REGDOMAIN_EVENT(devt, regCode) \
|
||||
ar6000_regDomain_event((devt), (regCode))
|
||||
|
||||
#define A_WMI_NEIGHBORREPORT_EVENT(devt, numAps, info) \
|
||||
ar6000_neighborReport_event((devt), (numAps), (info))
|
||||
|
||||
#define A_WMI_DISCONNECT_EVENT(devt, reason, bssid, assocRespLen, assocInfo, protocolReasonStatus) \
|
||||
ar6000_disconnect_event((devt), (reason), (bssid), (assocRespLen), (assocInfo), (protocolReasonStatus))
|
||||
|
||||
#define A_WMI_TKIP_MICERR_EVENT(devt, keyid, ismcast) \
|
||||
ar6000_tkip_micerr_event((devt), (keyid), (ismcast))
|
||||
|
||||
#define A_WMI_BITRATE_RX(devt, rateKbps) \
|
||||
ar6000_bitrate_rx((devt), (rateKbps))
|
||||
|
||||
#define A_WMI_TXPWR_RX(devt, txPwr) \
|
||||
ar6000_txPwr_rx((devt), (txPwr))
|
||||
|
||||
#define A_WMI_READY_EVENT(devt, datap, phyCap) \
|
||||
ar6000_ready_event((devt), (datap), (phyCap))
|
||||
|
||||
#define A_WMI_DBGLOG_INIT_DONE(ar) \
|
||||
ar6000_dbglog_init_done(ar);
|
||||
|
||||
#define A_WMI_RSSI_THRESHOLD_EVENT(devt, newThreshold, rssi) \
|
||||
ar6000_rssiThreshold_event((devt), (newThreshold), (rssi))
|
||||
|
||||
#define A_WMI_REPORT_ERROR_EVENT(devt, errorVal) \
|
||||
ar6000_reportError_event((devt), (errorVal))
|
||||
|
||||
#define A_WMI_ROAM_TABLE_EVENT(devt, pTbl) \
|
||||
ar6000_roam_tbl_event((devt), (pTbl))
|
||||
|
||||
#define A_WMI_ROAM_DATA_EVENT(devt, p) \
|
||||
ar6000_roam_data_event((devt), (p))
|
||||
|
||||
#define A_WMI_WOW_LIST_EVENT(devt, num_filters, wow_filters) \
|
||||
ar6000_wow_list_event((devt), (num_filters), (wow_filters))
|
||||
|
||||
#define A_WMI_CAC_EVENT(devt, ac, cac_indication, statusCode, tspecSuggestion) \
|
||||
ar6000_cac_event((devt), (ac), (cac_indication), (statusCode), (tspecSuggestion))
|
||||
|
||||
#define A_WMI_IPTOS_TO_USERPRIORITY(pkt) \
|
||||
ar6000_iptos_to_userPriority((pkt))
|
||||
|
||||
#define A_WMI_PMKID_LIST_EVENT(devt, num_pmkid, pmkid_list) \
|
||||
ar6000_pmkid_list_event((devt), (num_pmkid), (pmkid_list))
|
||||
|
||||
#ifdef CONFIG_HOST_GPIO_SUPPORT
|
||||
|
||||
#define A_WMI_GPIO_INTR_RX(intr_mask, input_values) \
|
||||
ar6000_gpio_intr_rx((intr_mask), (input_values))
|
||||
|
||||
#define A_WMI_GPIO_DATA_RX(reg_id, value) \
|
||||
ar6000_gpio_data_rx((reg_id), (value))
|
||||
|
||||
#define A_WMI_GPIO_ACK_RX() \
|
||||
ar6000_gpio_ack_rx()
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SEND_EVENT_TO_APP
|
||||
|
||||
#define A_WMI_SEND_EVENT_TO_APP(ar, eventId, datap, len) \
|
||||
ar6000_send_event_to_app((ar), (eventId), (datap), (len))
|
||||
|
||||
#else
|
||||
|
||||
#define A_WMI_SEND_EVENT_TO_APP(ar, eventId, datap, len)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
#define A_WMI_TCMD_RX_REPORT_EVENT(devt, results, len) \
|
||||
ar6000_tcmd_rx_report_event((devt), (results), (len))
|
||||
#endif
|
||||
|
||||
#define A_WMI_HBCHALLENGERESP_EVENT(devt, cookie, source) \
|
||||
ar6000_hbChallengeResp_event((devt), (cookie), (source))
|
||||
|
||||
#define A_WMI_TX_RETRY_ERR_EVENT(devt) \
|
||||
ar6000_tx_retry_err_event((devt))
|
||||
|
||||
#define A_WMI_SNR_THRESHOLD_EVENT_RX(devt, newThreshold, snr) \
|
||||
ar6000_snrThresholdEvent_rx((devt), (newThreshold), (snr))
|
||||
|
||||
#define A_WMI_LQ_THRESHOLD_EVENT_RX(devt, range, lqVal) \
|
||||
ar6000_lqThresholdEvent_rx((devt), (range), (lqVal))
|
||||
|
||||
#define A_WMI_RATEMASK_RX(devt, ratemask) \
|
||||
ar6000_ratemask_rx((devt), (ratemask))
|
||||
|
||||
#define A_WMI_KEEPALIVE_RX(devt, configured) \
|
||||
ar6000_keepalive_rx((devt), (configured))
|
||||
|
||||
#define A_WMI_BSSINFO_EVENT_RX(ar, datp, len) \
|
||||
ar6000_bssInfo_event_rx((ar), (datap), (len))
|
||||
|
||||
#define A_WMI_DBGLOG_EVENT(ar, dropped, buffer, length) \
|
||||
ar6000_dbglog_event((ar), (dropped), (buffer), (length));
|
||||
|
||||
#define A_WMI_STREAM_TX_ACTIVE(devt,trafficClass) \
|
||||
ar6000_indicate_tx_activity((devt),(trafficClass), TRUE)
|
||||
|
||||
#define A_WMI_STREAM_TX_INACTIVE(devt,trafficClass) \
|
||||
ar6000_indicate_tx_activity((devt),(trafficClass), FALSE)
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/** **/
|
||||
/** HTC related hooks **/
|
||||
/** **/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _A_OSAPI_H_
|
||||
#define _A_OSAPI_H_
|
||||
/*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_osapi.h#1 $
|
||||
*
|
||||
* This file contains the definitions of the basic atheros data types.
|
||||
* It is used to map the data types in atheros files to a platform specific
|
||||
* type.
|
||||
*
|
||||
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ar6000/osapi_linux.h"
|
||||
|
||||
#endif /* _OSAPI_H_ */
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _A_TYPES_H_
|
||||
#define _A_TYPES_H_
|
||||
/*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_types.h#1 $
|
||||
*
|
||||
* This file contains the definitions of the basic atheros data types.
|
||||
* It is used to map the data types in atheros files to a platform specific
|
||||
* type.
|
||||
*
|
||||
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ar6000/athtypes_linux.h"
|
||||
|
||||
#endif /* _ATHTYPES_H_ */
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef _AR6000_API_H_
|
||||
#define _AR6000_API_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file contains the API to access the OS dependent atheros host driver
|
||||
* by the WMI or WLAN generic modules.
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/ar6000_api.h#1 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ar6000/ar6xapi_linux.h"
|
||||
|
||||
#endif /* _AR6000_API_H */
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AR6000_DIAG_H_
|
||||
#define AR6000_DIAG_H_
|
||||
|
||||
|
||||
A_STATUS
|
||||
ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
|
||||
A_STATUS
|
||||
ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
|
||||
A_STATUS
|
||||
ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
|
||||
A_UCHAR *data, A_UINT32 length);
|
||||
|
||||
A_STATUS
|
||||
ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
|
||||
A_UCHAR *data, A_UINT32 length);
|
||||
|
||||
#endif /*AR6000_DIAG_H_*/
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef __ATHDEFS_H__
|
||||
#define __ATHDEFS_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This file contains definitions that may be used across both
|
||||
* Host and Target software. Nothing here is module-dependent
|
||||
* or platform-dependent.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generic error codes that can be used by hw, sta, ap, sim, dk
|
||||
* and any other environments. Since these are enums, feel free to
|
||||
* add any more codes that you need.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
A_ERROR = -1, /* Generic error return */
|
||||
A_OK = 0, /* success */
|
||||
/* Following values start at 1 */
|
||||
A_DEVICE_NOT_FOUND, /* not able to find PCI device */
|
||||
A_NO_MEMORY, /* not able to allocate memory, not available */
|
||||
A_MEMORY_NOT_AVAIL, /* memory region is not free for mapping */
|
||||
A_NO_FREE_DESC, /* no free descriptors available */
|
||||
A_BAD_ADDRESS, /* address does not match descriptor */
|
||||
A_WIN_DRIVER_ERROR, /* used in NT_HW version, if problem at init */
|
||||
A_REGS_NOT_MAPPED, /* registers not correctly mapped */
|
||||
A_EPERM, /* Not superuser */
|
||||
A_EACCES, /* Access denied */
|
||||
A_ENOENT, /* No such entry, search failed, etc. */
|
||||
A_EEXIST, /* The object already exists (can't create) */
|
||||
A_EFAULT, /* Bad address fault */
|
||||
A_EBUSY, /* Object is busy */
|
||||
A_EINVAL, /* Invalid parameter */
|
||||
A_EMSGSIZE, /* Inappropriate message buffer length */
|
||||
A_ECANCELED, /* Operation canceled */
|
||||
A_ENOTSUP, /* Operation not supported */
|
||||
A_ECOMM, /* Communication error on send */
|
||||
A_EPROTO, /* Protocol error */
|
||||
A_ENODEV, /* No such device */
|
||||
A_EDEVNOTUP, /* device is not UP */
|
||||
A_NO_RESOURCE, /* No resources for requested operation */
|
||||
A_HARDWARE, /* Hardware failure */
|
||||
A_PENDING, /* Asynchronous routine; will send up results la
|
||||
ter (typically in callback) */
|
||||
A_EBADCHANNEL, /* The channel cannot be used */
|
||||
A_DECRYPT_ERROR, /* Decryption error */
|
||||
A_PHY_ERROR, /* RX PHY error */
|
||||
A_CONSUMED /* Object was consumed */
|
||||
} A_STATUS;
|
||||
|
||||
#define A_SUCCESS(x) (x == A_OK)
|
||||
#define A_FAILED(x) (!A_SUCCESS(x))
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following definition is WLAN specific definition
|
||||
*/
|
||||
typedef enum {
|
||||
MODE_11A = 0, /* 11a Mode */
|
||||
MODE_11G = 1, /* 11g + 11b Mode */
|
||||
MODE_11B = 2, /* 11b Mode */
|
||||
MODE_11GONLY = 3, /* 11g only Mode */
|
||||
MODE_UNKNOWN = 4,
|
||||
MODE_MAX = 4
|
||||
} WLAN_PHY_MODE;
|
||||
|
||||
typedef enum {
|
||||
WLAN_11A_CAPABILITY = 1,
|
||||
WLAN_11G_CAPABILITY = 2,
|
||||
WLAN_11AG_CAPABILITY = 3,
|
||||
}WLAN_CAPABILITY;
|
||||
|
||||
#endif /* __ATHDEFS_H__ */
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ATHDRV_H_
|
||||
#define _ATHDRV_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ATHDRV_H_ */
|
|
@ -0,0 +1,41 @@
|
|||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
* @file: athendpack.h
|
||||
*
|
||||
* @abstract: end compiler-specific structure packing
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifdef VXWORKS
|
||||
#endif /* VXWORKS */
|
||||
|
||||
#ifdef LINUX
|
||||
#endif /* LINUX */
|
||||
|
||||
#ifdef QNX
|
||||
#endif /* QNX */
|
||||
|
||||
#ifdef INTEGRITY
|
||||
#include "integrity/athendpack_integrity.h"
|
||||
#endif /* INTEGRITY */
|
||||
|
||||
#ifdef NUCLEUS
|
||||
#endif /* NUCLEUS */
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#include "../os/wince/include/athendpack_wince.h"
|
||||
#endif /* WINCE */
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
* @file: athstartpack.h
|
||||
*
|
||||
* @abstract: start compiler-specific structure packing
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef VXWORKS
|
||||
#endif /* VXWORKS */
|
||||
|
||||
#ifdef LINUX
|
||||
#endif /* LINUX */
|
||||
|
||||
#ifdef QNX
|
||||
#endif /* QNX */
|
||||
|
||||
#ifdef INTEGRITY
|
||||
#include "integrity/athstartpack_integrity.h"
|
||||
#endif /* INTEGRITY */
|
||||
|
||||
#ifdef NUCLEUS
|
||||
#endif /* NUCLEUS */
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#include "../os/wince/include/athstartpack_wince.h"
|
||||
#endif /* WINCE */
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef _BMI_H_
|
||||
#define _BMI_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
* BMI declarations and prototypes
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Header files */
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "hif.h"
|
||||
#include "a_osapi.h"
|
||||
#include "bmi_msg.h"
|
||||
|
||||
void
|
||||
BMIInit(void);
|
||||
|
||||
A_STATUS
|
||||
BMIDone(HIF_DEVICE *device);
|
||||
|
||||
A_STATUS
|
||||
BMIGetTargetInfo(HIF_DEVICE *device, struct bmi_target_info *targ_info);
|
||||
|
||||
A_STATUS
|
||||
BMIReadMemory(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length);
|
||||
|
||||
A_STATUS
|
||||
BMIWriteMemory(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length);
|
||||
|
||||
A_STATUS
|
||||
BMIExecute(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 *param);
|
||||
|
||||
A_STATUS
|
||||
BMISetAppStart(HIF_DEVICE *device,
|
||||
A_UINT32 address);
|
||||
|
||||
A_STATUS
|
||||
BMIReadSOCRegister(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 *param);
|
||||
|
||||
A_STATUS
|
||||
BMIWriteSOCRegister(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UINT32 param);
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchInstall(HIF_DEVICE *device,
|
||||
A_UINT32 ROM_addr,
|
||||
A_UINT32 RAM_addr,
|
||||
A_UINT32 nbytes,
|
||||
A_UINT32 do_activate,
|
||||
A_UINT32 *patch_id);
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchUninstall(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_id);
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchActivate(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_count,
|
||||
A_UINT32 *rompatch_list);
|
||||
|
||||
A_STATUS
|
||||
BMIrompatchDeactivate(HIF_DEVICE *device,
|
||||
A_UINT32 rompatch_count,
|
||||
A_UINT32 *rompatch_list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BMI_H_ */
|
|
@ -0,0 +1,199 @@
|
|||
#ifndef __BMI_MSG_H__
|
||||
#define __BMI_MSG_H__
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bootloader Messaging Interface (BMI)
|
||||
*
|
||||
* BMI is a very simple messaging interface used during initialization
|
||||
* to read memory, write memory, execute code, and to define an
|
||||
* application entry PC.
|
||||
*
|
||||
* It is used to download an application to AR6K, to provide
|
||||
* patches to code that is already resident on AR6K, and generally
|
||||
* to examine and modify state. The Host has an opportunity to use
|
||||
* BMI only once during bootup. Once the Host issues a BMI_DONE
|
||||
* command, this opportunity ends.
|
||||
*
|
||||
* The Host writes BMI requests to mailbox0, and reads BMI responses
|
||||
* from mailbox0. BMI requests all begin with a command
|
||||
* (see below for specific commands), and are followed by
|
||||
* command-specific data.
|
||||
*
|
||||
* Flow control:
|
||||
* The Host can only issue a command once the Target gives it a
|
||||
* "BMI Command Credit", using AR6K Counter #4. As soon as the
|
||||
* Target has completed a command, it issues another BMI Command
|
||||
* Credit (so the Host can issue the next command).
|
||||
*
|
||||
* BMI handles all required Target-side cache flushing.
|
||||
*/
|
||||
|
||||
|
||||
/* Maximum data size used for BMI transfers */
|
||||
#define BMI_DATASZ_MAX 32
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
#define BMI_NO_COMMAND 0
|
||||
|
||||
#define BMI_DONE 1
|
||||
/*
|
||||
* Semantics: Host is done using BMI
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_DONE)
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_MEMORY 2
|
||||
/*
|
||||
* Semantics: Host reads AR6K memory
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_READ_MEMORY)
|
||||
* A_UINT32 address
|
||||
* A_UINT32 length, at most BMI_DATASZ_MAX
|
||||
* Response format:
|
||||
* A_UINT8 data[length]
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_MEMORY 3
|
||||
/*
|
||||
* Semantics: Host writes AR6K memory
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_WRITE_MEMORY)
|
||||
* A_UINT32 address
|
||||
* A_UINT32 length, at most BMI_DATASZ_MAX
|
||||
* A_UINT8 data[length]
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_EXECUTE 4
|
||||
/*
|
||||
* Semantics: Causes AR6K to execute code
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_EXECUTE)
|
||||
* A_UINT32 address
|
||||
* A_UINT32 parameter
|
||||
* Response format:
|
||||
* A_UINT32 return value
|
||||
*/
|
||||
|
||||
#define BMI_SET_APP_START 5
|
||||
/*
|
||||
* Semantics: Set Target application starting address
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_SET_APP_START)
|
||||
* A_UINT32 address
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_SOC_REGISTER 6
|
||||
/*
|
||||
* Semantics: Read a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_READ_REGISTER)
|
||||
* A_UINT32 address
|
||||
* Response format:
|
||||
* A_UINT32 value
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_SOC_REGISTER 7
|
||||
/*
|
||||
* Semantics: Write a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_WRITE_REGISTER)
|
||||
* A_UINT32 address
|
||||
* A_UINT32 value
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_GET_TARGET_ID 8
|
||||
#define BMI_GET_TARGET_INFO 8
|
||||
/*
|
||||
* Semantics: Fetch the 4-byte Target information
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_GET_TARGET_ID/INFO)
|
||||
* Response format1 (old firmware):
|
||||
* A_UINT32 TargetVersionID
|
||||
* Response format2 (newer firmware):
|
||||
* A_UINT32 TARGET_VERSION_SENTINAL
|
||||
* struct bmi_target_info;
|
||||
*/
|
||||
|
||||
struct bmi_target_info {
|
||||
A_UINT32 target_info_byte_count; /* size of this structure */
|
||||
A_UINT32 target_ver; /* Target Version ID */
|
||||
A_UINT32 target_type; /* Target type */
|
||||
};
|
||||
#define TARGET_VERSION_SENTINAL 0xffffffff
|
||||
#define TARGET_TYPE_AR6001 1
|
||||
#define TARGET_TYPE_AR6002 2
|
||||
|
||||
|
||||
#define BMI_ROMPATCH_INSTALL 9
|
||||
/*
|
||||
* Semantics: Install a ROM Patch.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_ROMPATCH_INSTALL)
|
||||
* A_UINT32 Target ROM Address
|
||||
* A_UINT32 Target RAM Address
|
||||
* A_UINT32 Size, in bytes
|
||||
* A_UINT32 Activate? 1-->activate;
|
||||
* 0-->install but do not activate
|
||||
* Response format:
|
||||
* A_UINT32 PatchID
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_UNINSTALL 10
|
||||
/*
|
||||
* Semantics: Uninstall a previously-installed ROM Patch,
|
||||
* automatically deactivating, if necessary.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_ROMPATCH_UNINSTALL)
|
||||
* A_UINT32 PatchID
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_ACTIVATE 11
|
||||
/*
|
||||
* Semantics: Activate a list of previously-installed ROM Patches.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_ROMPATCH_ACTIVATE)
|
||||
* A_UINT32 rompatch_count
|
||||
* A_UINT32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_DEACTIVATE 12
|
||||
/*
|
||||
* Semantics: Deactivate a list of active ROM Patches.
|
||||
* Request format:
|
||||
* A_UINT32 command (BMI_ROMPATCH_DEACTIVATE)
|
||||
* A_UINT32 rompatch_count
|
||||
* A_UINT32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
|
||||
#endif /* __BMI_MSG_H__ */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef COMMON_DRV_H_
|
||||
#define COMMON_DRV_H_
|
||||
|
||||
#include "hif.h"
|
||||
#include "htc_packet.h"
|
||||
|
||||
|
||||
|
||||
/* structure that is the state information for the default credit distribution callback
|
||||
* drivers should instantiate (zero-init as well) this structure in their driver instance
|
||||
* and pass it as a context to the HTC credit distribution functions */
|
||||
typedef struct _COMMON_CREDIT_STATE_INFO {
|
||||
int TotalAvailableCredits; /* total credits in the system at startup */
|
||||
int CurrentFreeCredits; /* credits available in the pool that have not been
|
||||
given out to endpoints */
|
||||
HTC_ENDPOINT_CREDIT_DIST *pLowestPriEpDist; /* pointer to the lowest priority endpoint dist struct */
|
||||
} COMMON_CREDIT_STATE_INFO;
|
||||
|
||||
|
||||
/* HTC TX packet tagging definitions */
|
||||
#define AR6K_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
|
||||
#define AR6K_DATA_PKT_TAG (AR6K_CONTROL_PKT_TAG + 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* OS-independent APIs */
|
||||
A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo);
|
||||
A_STATUS ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
A_STATUS ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
|
||||
A_STATUS ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address, A_UCHAR *data, A_UINT32 length);
|
||||
A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType);
|
||||
void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType);
|
||||
A_STATUS ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*COMMON_DRV_H_*/
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This file contains the definitions and data structures associated with
|
||||
* the log based debug mechanism.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DBGLOG_H_
|
||||
#define _DBGLOG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DBGLOG_TIMESTAMP_OFFSET 0
|
||||
#define DBGLOG_TIMESTAMP_MASK 0x0000FFFF /* Bit 0-15. Contains bit
|
||||
8-23 of the LF0 timer */
|
||||
#define DBGLOG_DBGID_OFFSET 16
|
||||
#define DBGLOG_DBGID_MASK 0x03FF0000 /* Bit 16-25 */
|
||||
#define DBGLOG_DBGID_NUM_MAX 256 /* Upper limit is width of mask */
|
||||
|
||||
#define DBGLOG_MODULEID_OFFSET 26
|
||||
#define DBGLOG_MODULEID_MASK 0x3C000000 /* Bit 26-29 */
|
||||
#define DBGLOG_MODULEID_NUM_MAX 16 /* Upper limit is width of mask */
|
||||
|
||||
/*
|
||||
* Please ensure that the definition of any new module intrduced is captured
|
||||
* between the DBGLOG_MODULEID_START and DBGLOG_MODULEID_END defines. The
|
||||
* structure is required for the parser to correctly pick up the values for
|
||||
* different modules.
|
||||
*/
|
||||
#define DBGLOG_MODULEID_START
|
||||
#define DBGLOG_MODULEID_INF 0
|
||||
#define DBGLOG_MODULEID_WMI 1
|
||||
#define DBGLOG_MODULEID_CSERV 2
|
||||
#define DBGLOG_MODULEID_PM 3
|
||||
#define DBGLOG_MODULEID_TXRX_MGMTBUF 4
|
||||
#define DBGLOG_MODULEID_TXRX_TXBUF 5
|
||||
#define DBGLOG_MODULEID_TXRX_RXBUF 6
|
||||
#define DBGLOG_MODULEID_WOW 7
|
||||
#define DBGLOG_MODULEID_WHAL 8
|
||||
#define DBGLOG_MODULEID_END
|
||||
|
||||
#define DBGLOG_NUM_ARGS_OFFSET 30
|
||||
#define DBGLOG_NUM_ARGS_MASK 0xC0000000 /* Bit 30-31 */
|
||||
#define DBGLOG_NUM_ARGS_MAX 2 /* Upper limit is width of mask */
|
||||
|
||||
#define DBGLOG_MODULE_LOG_ENABLE_OFFSET 0
|
||||
#define DBGLOG_MODULE_LOG_ENABLE_MASK 0x0000FFFF
|
||||
|
||||
#define DBGLOG_REPORTING_ENABLED_OFFSET 16
|
||||
#define DBGLOG_REPORTING_ENABLED_MASK 0x00010000
|
||||
|
||||
#define DBGLOG_TIMESTAMP_RESOLUTION_OFFSET 17
|
||||
#define DBGLOG_TIMESTAMP_RESOLUTION_MASK 0x000E0000
|
||||
|
||||
#define DBGLOG_REPORT_SIZE_OFFSET 20
|
||||
#define DBGLOG_REPORT_SIZE_MASK 0x3FF00000
|
||||
|
||||
#define DBGLOG_LOG_BUFFER_SIZE 1500
|
||||
#define DBGLOG_DBGID_DEFINITION_LEN_MAX 64
|
||||
|
||||
struct dbglog_buf_s {
|
||||
struct dbglog_buf_s *next;
|
||||
A_INT8 *buffer;
|
||||
A_UINT32 bufsize;
|
||||
A_UINT32 length;
|
||||
A_UINT32 count;
|
||||
A_UINT32 free;
|
||||
};
|
||||
|
||||
struct dbglog_hdr_s {
|
||||
struct dbglog_buf_s *dbuf;
|
||||
A_UINT32 dropped;
|
||||
};
|
||||
|
||||
struct dbglog_config_s {
|
||||
A_UINT32 cfgvalid; /* Mask with valid config bits */
|
||||
union {
|
||||
/* TODO: Take care of endianness */
|
||||
struct {
|
||||
A_UINT32 mmask:16; /* Mask of modules with logging on */
|
||||
A_UINT32 rep:1; /* Reporting enabled or not */
|
||||
A_UINT32 tsr:3; /* Time stamp resolution. Def: 1 ms */
|
||||
A_UINT32 size:10; /* Report size in number of messages */
|
||||
A_UINT32 reserved:2;
|
||||
} dbglog_config;
|
||||
|
||||
A_UINT32 value;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define cfgmmask u.dbglog_config.mmask
|
||||
#define cfgrep u.dbglog_config.rep
|
||||
#define cfgtsr u.dbglog_config.tsr
|
||||
#define cfgsize u.dbglog_config.size
|
||||
#define cfgvalue u.value
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DBGLOG_H_ */
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef _DBGLOG_API_H_
|
||||
#define _DBGLOG_API_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
* This file contains host side debug primitives.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "dbglog.h"
|
||||
|
||||
#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE
|
||||
|
||||
#define DBGLOG_GET_DBGID(arg) \
|
||||
((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET)
|
||||
|
||||
#define DBGLOG_GET_MODULEID(arg) \
|
||||
((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET)
|
||||
|
||||
#define DBGLOG_GET_NUMARGS(arg) \
|
||||
((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET)
|
||||
|
||||
#define DBGLOG_GET_TIMESTAMP(arg) \
|
||||
((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DBGLOG_API_H_ */
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This file contains the definitions of the debug identifiers for different
|
||||
* modules.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DBGLOG_ID_H_
|
||||
#define _DBGLOG_ID_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The nomenclature for the debug identifiers is MODULE_DESCRIPTION.
|
||||
* Please ensure that the definition of any new debugid introduced is captured
|
||||
* between the <MODULE>_DBGID_DEFINITION_START and
|
||||
* <MODULE>_DBGID_DEFINITION_END defines. The structure is required for the
|
||||
* parser to correctly pick up the values for different debug identifiers.
|
||||
*/
|
||||
|
||||
/* INF debug identifier definitions */
|
||||
#define INF_DBGID_DEFINITION_START
|
||||
#define INF_ASSERTION_FAILED 1
|
||||
#define INF_TARGET_ID 2
|
||||
#define INF_DBGID_DEFINITION_END
|
||||
|
||||
/* WMI debug identifier definitions */
|
||||
#define WMI_DBGID_DEFINITION_START
|
||||
#define WMI_CMD_RX_XTND_PKT_TOO_SHORT 1
|
||||
#define WMI_EXTENDED_CMD_NOT_HANDLED 2
|
||||
#define WMI_CMD_RX_PKT_TOO_SHORT 3
|
||||
#define WMI_CALLING_WMI_EXTENSION_FN 4
|
||||
#define WMI_CMD_NOT_HANDLED 5
|
||||
#define WMI_IN_SYNC 6
|
||||
#define WMI_TARGET_WMI_SYNC_CMD 7
|
||||
#define WMI_SET_SNR_THRESHOLD_PARAMS 8
|
||||
#define WMI_SET_RSSI_THRESHOLD_PARAMS 9
|
||||
#define WMI_SET_LQ_TRESHOLD_PARAMS 10
|
||||
#define WMI_TARGET_CREATE_PSTREAM_CMD 11
|
||||
#define WMI_WI_DTM_INUSE 12
|
||||
#define WMI_TARGET_DELETE_PSTREAM_CMD 13
|
||||
#define WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD 14
|
||||
#define WMI_TARGET_GET_BIT_RATE_CMD 15
|
||||
#define WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS 16
|
||||
#define WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD 17
|
||||
#define WMI_TARGET_GET_TX_PWR_CMD 18
|
||||
#define WMI_FREE_EVBUF_WMIBUF 19
|
||||
#define WMI_FREE_EVBUF_DATABUF 20
|
||||
#define WMI_FREE_EVBUF_BADFLAG 21
|
||||
#define WMI_HTC_RX_ERROR_DATA_PACKET 22
|
||||
#define WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX 23
|
||||
#define WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT 24
|
||||
#define WMI_SENDING_READY_EVENT 25
|
||||
#define WMI_SETPOWER_MDOE_TO_MAXPERF 26
|
||||
#define WMI_SETPOWER_MDOE_TO_REC 27
|
||||
#define WMI_BSSINFO_EVENT_FROM 28
|
||||
#define WMI_TARGET_GET_STATS_CMD 29
|
||||
#define WMI_SENDING_SCAN_COMPLETE_EVENT 30
|
||||
#define WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT 31
|
||||
#define WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT 32
|
||||
#define WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT 33
|
||||
#define WMI_SENDING_ERROR_REPORT_EVENT 34
|
||||
#define WMI_SENDING_CAC_EVENT 35
|
||||
#define WMI_TARGET_GET_ROAM_TABLE_CMD 36
|
||||
#define WMI_TARGET_GET_ROAM_DATA_CMD 37
|
||||
#define WMI_SENDING_GPIO_INTR_EVENT 38
|
||||
#define WMI_SENDING_GPIO_ACK_EVENT 39
|
||||
#define WMI_SENDING_GPIO_DATA_EVENT 40
|
||||
#define WMI_CMD_RX 41
|
||||
#define WMI_CMD_RX_XTND 42
|
||||
#define WMI_EVENT_SEND 43
|
||||
#define WMI_EVENT_SEND_XTND 44
|
||||
#define WMI_DBGID_DEFINITION_END
|
||||
|
||||
/* CSERV debug identifier definitions */
|
||||
#define CSERV_DBGID_DEFINITION_START
|
||||
#define CSERV_BEGIN_SCAN1 1
|
||||
#define CSERV_BEGIN_SCAN2 2
|
||||
#define CSERV_END_SCAN1 3
|
||||
#define CSERV_END_SCAN2 4
|
||||
#define CSERV_CHAN_SCAN_START 5
|
||||
#define CSERV_CHAN_SCAN_STOP 6
|
||||
#define CSERV_CHANNEL_OPPPORTUNITY 7
|
||||
#define CSERV_NC_TIMEOUT 8
|
||||
#define CSERV_BACK_HOME 10
|
||||
#define CSERV_CHMGR_CH_CALLBACK1 11
|
||||
#define CSERV_CHMGR_CH_CALLBACK2 12
|
||||
#define CSERV_CHMGR_CH_CALLBACK3 13
|
||||
#define CSERV_SET_SCAN_PARAMS1 14
|
||||
#define CSERV_SET_SCAN_PARAMS2 15
|
||||
#define CSERV_SET_SCAN_PARAMS3 16
|
||||
#define CSERV_SET_SCAN_PARAMS4 17
|
||||
#define CSERV_ABORT_SCAN 18
|
||||
#define CSERV_NEWSTATE 19
|
||||
#define CSERV_MINCHMGR_OP_END 20
|
||||
#define CSERV_CHMGR_OP_END 21
|
||||
#define CSERV_DISCONNECT_TIMEOUT 22
|
||||
#define CSERV_ROAM_TIMEOUT 23
|
||||
#define CSERV_FORCE_SCAN1 24
|
||||
#define CSERV_FORCE_SCAN2 25
|
||||
#define CSERV_FORCE_SCAN3 26
|
||||
#define CSERV_UTIL_TIMEOUT 27
|
||||
#define CSERV_RSSIPOLLER 28
|
||||
#define CSERV_RETRY_CONNECT_TIMEOUT 29
|
||||
#define CSERV_RSSIINDBMPOLLER 30
|
||||
#define CSERV_BGSCAN_ENABLE 31
|
||||
#define CSERV_BGSCAN_DISABLE 32
|
||||
#define CSERV_WLAN_START_SCAN_CMD1 33
|
||||
#define CSERV_WLAN_START_SCAN_CMD2 34
|
||||
#define CSERV_WLAN_START_SCAN_CMD3 35
|
||||
#define CSERV_START_SCAN_CMD 36
|
||||
#define CSERV_START_FORCE_SCAN 37
|
||||
#define CSERV_NEXT_CHAN 38
|
||||
#define CSERV_SET_REGCODE 39
|
||||
#define CSERV_START_ADHOC 40
|
||||
#define CSERV_ADHOC_AT_HOME 41
|
||||
#define CSERV_OPT_AT_HOME 42
|
||||
#define CSERV_WLAN_CONNECT_CMD 43
|
||||
#define CSERV_WLAN_RECONNECT_CMD 44
|
||||
#define CSERV_WLAN_DISCONNECT_CMD 45
|
||||
#define CSERV_BSS_CHANGE_CHANNEL 46
|
||||
#define CSERV_BEACON_RX 47
|
||||
#define CSERV_KEEPALIVE_CHECK 48
|
||||
#define CSERV_RC_BEGIN_SCAN 49
|
||||
#define CSERV_RC_SCAN_START 50
|
||||
#define CSERV_RC_SCAN_STOP 51
|
||||
#define CSERV_RC_NEXT 52
|
||||
#define CSERV_RC_SCAN_END 53
|
||||
#define CSERV_PROBE_CALLBACK 54
|
||||
#define CSERV_ROAM1 55
|
||||
#define CSERV_ROAM2 56
|
||||
#define CSERV_ROAM3 57
|
||||
#define CSERV_CONNECT_EVENT 58
|
||||
#define CSERV_DISCONNECT_EVENT 59
|
||||
#define CSERV_BMISS_HANDLER1 60
|
||||
#define CSERV_BMISS_HANDLER2 61
|
||||
#define CSERV_BMISS_HANDLER3 62
|
||||
#define CSERV_LOWRSSI_HANDLER 63
|
||||
#define CSERV_WLAN_SET_PMKID_CMD 64
|
||||
#define CSERV_RECONNECT_REQUEST 65
|
||||
#define CSERV_KEYSPLUMBED_EVENT 66
|
||||
#define CSERV_NEW_REG 67
|
||||
#define CSERV_SET_RSSI_THOLD 68
|
||||
#define CSERV_RSSITHRESHOLDCHECK 69
|
||||
#define CSERV_RSSIINDBMTHRESHOLDCHECK 70
|
||||
#define CSERV_WLAN_SET_OPT_CMD1 71
|
||||
#define CSERV_WLAN_SET_OPT_CMD2 72
|
||||
#define CSERV_WLAN_SET_OPT_CMD3 73
|
||||
#define CSERV_WLAN_SET_OPT_CMD4 74
|
||||
#define CSERV_SCAN_CONNECT_STOP 75
|
||||
#define CSERV_BMISS_HANDLER4 76
|
||||
#define CSERV_INITIALIZE_TIMER 77
|
||||
#define CSERV_ARM_TIMER 78
|
||||
#define CSERV_DISARM_TIMER 79
|
||||
#define CSERV_UNINITIALIZE_TIMER 80
|
||||
#define CSERV_DISCONNECT_EVENT2 81
|
||||
#define CSERV_SCAN_CONNECT_START 82
|
||||
#define CSERV_BSSINFO_MEMORY_ALLOC_FAILED 83
|
||||
#define CSERV_SET_SCAN_PARAMS5 84
|
||||
#define CSERV_DBGID_DEFINITION_END
|
||||
|
||||
/* TXRX debug identifier definitions */
|
||||
#define TXRX_TXBUF_DBGID_DEFINITION_START
|
||||
#define TXRX_TXBUF_ALLOCATE_BUF 1
|
||||
#define TXRX_TXBUF_QUEUE_BUF_TO_MBOX 2
|
||||
#define TXRX_TXBUF_QUEUE_BUF_TO_TXQ 3
|
||||
#define TXRX_TXBUF_TXQ_DEPTH 4
|
||||
#define TXRX_TXBUF_IBSS_QUEUE_TO_SFQ 5
|
||||
#define TXRX_TXBUF_IBSS_QUEUE_TO_TXQ_FRM_SFQ 6
|
||||
#define TXRX_TXBUF_INITIALIZE_TIMER 7
|
||||
#define TXRX_TXBUF_ARM_TIMER 8
|
||||
#define TXRX_TXBUF_DISARM_TIMER 9
|
||||
#define TXRX_TXBUF_UNINITIALIZE_TIMER 10
|
||||
#define TXRX_TXBUF_DBGID_DEFINITION_END
|
||||
|
||||
#define TXRX_RXBUF_DBGID_DEFINITION_START
|
||||
#define TXRX_RXBUF_ALLOCATE_BUF 1
|
||||
#define TXRX_RXBUF_QUEUE_TO_HOST 2
|
||||
#define TXRX_RXBUF_QUEUE_TO_WLAN 3
|
||||
#define TXRX_RXBUF_ZERO_LEN_BUF 4
|
||||
#define TXRX_RXBUF_QUEUE_TO_HOST_LASTBUF_IN_RXCHAIN 5
|
||||
#define TXRX_RXBUF_LASTBUF_IN_RXCHAIN_ZEROBUF 6
|
||||
#define TXRX_RXBUF_QUEUE_EMPTY_QUEUE_TO_WLAN 7
|
||||
#define TXRX_RXBUF_SEND_TO_RECV_MGMT 8
|
||||
#define TXRX_RXBUF_SEND_TO_IEEE_LAYER 9
|
||||
#define TXRX_RXBUF_DBGID_DEFINITION_END
|
||||
|
||||
#define TXRX_MGMTBUF_DBGID_DEFINITION_START
|
||||
#define TXRX_MGMTBUF_ALLOCATE_BUF 1
|
||||
#define TXRX_MGMTBUF_ALLOCATE_SM_BUF 2
|
||||
#define TXRX_MGMTBUF_ALLOCATE_RMBUF 3
|
||||
#define TXRX_MGMTBUF_GET_BUF 4
|
||||
#define TXRX_MGMTBUF_GET_SM_BUF 5
|
||||
#define TXRX_MGMTBUF_QUEUE_BUF_TO_TXQ 6
|
||||
#define TXRX_MGMTBUF_REAPED_BUF 7
|
||||
#define TXRX_MGMTBUF_REAPED_SM_BUF 8
|
||||
#define TXRX_MGMTBUF_WAIT_FOR_TXQ_DRAIN 9
|
||||
#define TXRX_MGMTBUF_WAIT_FOR_TXQ_SFQ_DRAIN 10
|
||||
#define TXRX_MGMTBUF_ENQUEUE_INTO_SFQ 11
|
||||
#define TXRX_MGMTBUF_DEQUEUE_FROM_SFQ 12
|
||||
#define TXRX_MGMTBUF_PAUSE_TXQ 13
|
||||
#define TXRX_MGMTBUF_RESUME_TXQ 14
|
||||
#define TXRX_MGMTBUF_WAIT_FORTXQ_DRAIN_TIMEOUT 15
|
||||
#define TXRX_MGMTBUF_DRAINQ 16
|
||||
#define TXRX_MGMTBUF_INDICATE_Q_DRAINED 17
|
||||
#define TXRX_MGMTBUF_DBGID_DEFINITION_END
|
||||
|
||||
/* PM (Power Module) debug identifier definitions */
|
||||
#define PM_DBGID_DEFINITION_START
|
||||
#define PM_INIT 1
|
||||
#define PM_ENABLE 2
|
||||
#define PM_SET_STATE 3
|
||||
#define PM_SET_POWERMODE 4
|
||||
#define PM_CONN_NOTIFY 5
|
||||
#define PM_REF_COUNT_NEGATIVE 6
|
||||
#define PM_APSD_ENABLE 7
|
||||
#define PM_UPDATE_APSD_STATE 8
|
||||
#define PM_CHAN_OP_REQ 9
|
||||
#define PM_SET_MY_BEACON_POLICY 10
|
||||
#define PM_SET_ALL_BEACON_POLICY 11
|
||||
#define PM_SET_PM_PARAMS1 12
|
||||
#define PM_SET_PM_PARAMS2 13
|
||||
#define PM_ADHOC_SET_PM_CAPS_FAIL 14
|
||||
#define PM_ADHOC_UNKNOWN_IBSS_ATTRIB_ID 15
|
||||
#define PM_DBGID_DEFINITION_END
|
||||
|
||||
/* Wake on Wireless debug identifier definitions */
|
||||
#define WOW_DBGID_DEFINITION_START
|
||||
#define WOW_INIT 1
|
||||
#define WOW_GET_CONFIG_DSET 2
|
||||
#define WOW_NO_CONFIG_DSET 3
|
||||
#define WOW_INVALID_CONFIG_DSET 4
|
||||
#define WOW_USE_DEFAULT_CONFIG 5
|
||||
#define WOW_SETUP_GPIO 6
|
||||
#define WOW_INIT_DONE 7
|
||||
#define WOW_SET_GPIO_PIN 8
|
||||
#define WOW_CLEAR_GPIO_PIN 9
|
||||
#define WOW_SET_WOW_MODE_CMD 10
|
||||
#define WOW_SET_HOST_MODE_CMD 11
|
||||
#define WOW_ADD_WOW_PATTERN_CMD 12
|
||||
#define WOW_NEW_WOW_PATTERN_AT_INDEX 13
|
||||
#define WOW_DEL_WOW_PATTERN_CMD 14
|
||||
#define WOW_LIST_CONTAINS_PATTERNS 15
|
||||
#define WOW_GET_WOW_LIST_CMD 16
|
||||
#define WOW_INVALID_FILTER_ID 17
|
||||
#define WOW_INVALID_FILTER_LISTID 18
|
||||
#define WOW_NO_VALID_FILTER_AT_ID 19
|
||||
#define WOW_NO_VALID_LIST_AT_ID 20
|
||||
#define WOW_NUM_PATTERNS_EXCEEDED 21
|
||||
#define WOW_NUM_LISTS_EXCEEDED 22
|
||||
#define WOW_GET_WOW_STATS 23
|
||||
#define WOW_CLEAR_WOW_STATS 24
|
||||
#define WOW_WAKEUP_HOST 25
|
||||
#define WOW_EVENT_WAKEUP_HOST 26
|
||||
#define WOW_EVENT_DISCARD 27
|
||||
#define WOW_PATTERN_MATCH 28
|
||||
#define WOW_PATTERN_NOT_MATCH 29
|
||||
#define WOW_PATTERN_NOT_MATCH_OFFSET 30
|
||||
#define WOW_DISABLED_HOST_ASLEEP 31
|
||||
#define WOW_ENABLED_HOST_ASLEEP_NO_PATTERNS 32
|
||||
#define WOW_ENABLED_HOST_ASLEEP_NO_MATCH_FOUND 33
|
||||
#define WOW_DBGID_DEFINITION_END
|
||||
|
||||
/* WHAL debug identifier definitions */
|
||||
#define WHAL_DBGID_DEFINITION_START
|
||||
#define WHAL_ERROR_ANI_CONTROL 1
|
||||
#define WHAL_ERROR_CHIP_TEST1 2
|
||||
#define WHAL_ERROR_CHIP_TEST2 3
|
||||
#define WHAL_ERROR_EEPROM_CHECKSUM 4
|
||||
#define WHAL_ERROR_EEPROM_MACADDR 5
|
||||
#define WHAL_ERROR_INTERRUPT_HIU 6
|
||||
#define WHAL_ERROR_KEYCACHE_RESET 7
|
||||
#define WHAL_ERROR_KEYCACHE_SET 8
|
||||
#define WHAL_ERROR_KEYCACHE_TYPE 9
|
||||
#define WHAL_ERROR_KEYCACHE_TKIPENTRY 10
|
||||
#define WHAL_ERROR_KEYCACHE_WEPLENGTH 11
|
||||
#define WHAL_ERROR_PHY_INVALID_CHANNEL 12
|
||||
#define WHAL_ERROR_POWER_AWAKE 13
|
||||
#define WHAL_ERROR_POWER_SET 14
|
||||
#define WHAL_ERROR_RECV_STOPDMA 15
|
||||
#define WHAL_ERROR_RECV_STOPPCU 16
|
||||
#define WHAL_ERROR_RESET_CHANNF1 17
|
||||
#define WHAL_ERROR_RESET_CHANNF2 18
|
||||
#define WHAL_ERROR_RESET_PM 19
|
||||
#define WHAL_ERROR_RESET_OFFSETCAL 20
|
||||
#define WHAL_ERROR_RESET_RFGRANT 21
|
||||
#define WHAL_ERROR_RESET_RXFRAME 22
|
||||
#define WHAL_ERROR_RESET_STOPDMA 23
|
||||
#define WHAL_ERROR_RESET_RECOVER 24
|
||||
#define WHAL_ERROR_XMIT_COMPUTE 25
|
||||
#define WHAL_ERROR_XMIT_NOQUEUE 26
|
||||
#define WHAL_ERROR_XMIT_ACTIVEQUEUE 27
|
||||
#define WHAL_ERROR_XMIT_BADTYPE 28
|
||||
#define WHAL_DBGID_DEFINITION_END
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DBGLOG_ID_H_ */
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
*
|
||||
* Double-link list definitions (adapted from Atheros SDIO stack)
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef __DL_LIST_H___
|
||||
#define __DL_LIST_H___
|
||||
|
||||
#define A_CONTAINING_STRUCT(address, struct_type, field_name)\
|
||||
((struct_type *)((A_UINT32)(address) - (A_UINT32)(&((struct_type *)0)->field_name)))
|
||||
|
||||
/* list functions */
|
||||
/* pointers for the list */
|
||||
typedef struct _DL_LIST {
|
||||
struct _DL_LIST *pPrev;
|
||||
struct _DL_LIST *pNext;
|
||||
}DL_LIST, *PDL_LIST;
|
||||
/*
|
||||
* DL_LIST_INIT , initialize doubly linked list
|
||||
*/
|
||||
#define DL_LIST_INIT(pList)\
|
||||
{(pList)->pPrev = pList; (pList)->pNext = pList;}
|
||||
|
||||
#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList)))
|
||||
#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext
|
||||
#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev
|
||||
/*
|
||||
* ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member
|
||||
* NOT: do not use this function if the items in the list are deleted inside the
|
||||
* iteration loop
|
||||
*/
|
||||
#define ITERATE_OVER_LIST(pStart, pTemp) \
|
||||
for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext)
|
||||
|
||||
|
||||
/* safe iterate macro that allows the item to be removed from the list
|
||||
* the iteration continues to the next item in the list
|
||||
*/
|
||||
#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \
|
||||
{ \
|
||||
PDL_LIST pTemp; \
|
||||
pTemp = (pStart)->pNext; \
|
||||
while (pTemp != (pStart)) { \
|
||||
(pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \
|
||||
pTemp = pTemp->pNext; \
|
||||
|
||||
#define ITERATE_END }}
|
||||
|
||||
/*
|
||||
* DL_ListInsertTail - insert pAdd to the end of the list
|
||||
*/
|
||||
static INLINE PDL_LIST DL_ListInsertTail(PDL_LIST pList, PDL_LIST pAdd) {
|
||||
/* insert at tail */
|
||||
pAdd->pPrev = pList->pPrev;
|
||||
pAdd->pNext = pList;
|
||||
pList->pPrev->pNext = pAdd;
|
||||
pList->pPrev = pAdd;
|
||||
return pAdd;
|
||||
}
|
||||
|
||||
/*
|
||||
* DL_ListInsertHead - insert pAdd into the head of the list
|
||||
*/
|
||||
static INLINE PDL_LIST DL_ListInsertHead(PDL_LIST pList, PDL_LIST pAdd) {
|
||||
/* insert at head */
|
||||
pAdd->pPrev = pList;
|
||||
pAdd->pNext = pList->pNext;
|
||||
pList->pNext->pPrev = pAdd;
|
||||
pList->pNext = pAdd;
|
||||
return pAdd;
|
||||
}
|
||||
|
||||
#define DL_ListAdd(pList,pItem) DL_ListInsertHead((pList),(pItem))
|
||||
/*
|
||||
* DL_ListRemove - remove pDel from list
|
||||
*/
|
||||
static INLINE PDL_LIST DL_ListRemove(PDL_LIST pDel) {
|
||||
pDel->pNext->pPrev = pDel->pPrev;
|
||||
pDel->pPrev->pNext = pDel->pNext;
|
||||
/* point back to itself just to be safe, incase remove is called again */
|
||||
pDel->pNext = pDel;
|
||||
pDel->pPrev = pDel;
|
||||
return pDel;
|
||||
}
|
||||
|
||||
/*
|
||||
* DL_ListRemoveItemFromHead - get a list item from the head
|
||||
*/
|
||||
static INLINE PDL_LIST DL_ListRemoveItemFromHead(PDL_LIST pList) {
|
||||
PDL_LIST pItem = NULL;
|
||||
if (pList->pNext != pList) {
|
||||
pItem = pList->pNext;
|
||||
/* remove the first item from head */
|
||||
DL_ListRemove(pItem);
|
||||
}
|
||||
return pItem;
|
||||
}
|
||||
|
||||
#endif /* __DL_LIST_H___ */
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/dset_api.h#1 $
|
||||
*
|
||||
* Host-side DataSet API.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DSET_API_H_
|
||||
#define _DSET_API_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Host-side DataSet support is optional, and is not
|
||||
* currently required for correct operation. To disable
|
||||
* Host-side DataSet support, set this to 0.
|
||||
*/
|
||||
#ifndef CONFIG_HOST_DSET_SUPPORT
|
||||
#define CONFIG_HOST_DSET_SUPPORT 1
|
||||
#endif
|
||||
|
||||
/* Called to send a DataSet Open Reply back to the Target. */
|
||||
A_STATUS wmi_dset_open_reply(struct wmi_t *wmip,
|
||||
A_UINT32 status,
|
||||
A_UINT32 access_cookie,
|
||||
A_UINT32 size,
|
||||
A_UINT32 version,
|
||||
A_UINT32 targ_handle,
|
||||
A_UINT32 targ_reply_fn,
|
||||
A_UINT32 targ_reply_arg);
|
||||
|
||||
/* Called to send a DataSet Data Reply back to the Target. */
|
||||
A_STATUS wmi_dset_data_reply(struct wmi_t *wmip,
|
||||
A_UINT32 status,
|
||||
A_UINT8 *host_buf,
|
||||
A_UINT32 length,
|
||||
A_UINT32 targ_buf,
|
||||
A_UINT32 targ_reply_fn,
|
||||
A_UINT32 targ_reply_arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* _DSET_API_H_ */
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DSET_INTERNAL_H__
|
||||
#define __DSET_INTERNAL_H__
|
||||
|
||||
/*
|
||||
* Internal dset definitions, common for DataSet layer.
|
||||
*/
|
||||
|
||||
#define DSET_TYPE_STANDARD 0
|
||||
#define DSET_TYPE_BPATCHED 1
|
||||
#define DSET_TYPE_COMPRESSED 2
|
||||
|
||||
/* Dataset descriptor */
|
||||
|
||||
typedef struct dset_descriptor_s {
|
||||
struct dset_descriptor_s *next; /* List link. NULL only at the last
|
||||
descriptor */
|
||||
A_UINT16 id; /* Dset ID */
|
||||
A_UINT16 size; /* Dset size. */
|
||||
void *DataPtr; /* Pointer to raw data for standard
|
||||
DataSet or pointer to original
|
||||
dset_descriptor for patched
|
||||
DataSet */
|
||||
A_UINT32 data_type; /* DSET_TYPE_*, above */
|
||||
|
||||
void *AuxPtr; /* Additional data that might
|
||||
needed for data_type. For
|
||||
example, pointer to patch
|
||||
Dataset descriptor for BPatch. */
|
||||
} dset_descriptor_t;
|
||||
|
||||
#endif /* __DSET_INTERNAL_H__ */
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DSETID_H__
|
||||
#define __DSETID_H__
|
||||
|
||||
/* Well-known DataSet IDs */
|
||||
#define DSETID_UNUSED 0x00000000
|
||||
#define DSETID_BOARD_DATA 0x00000001 /* Cal and board data */
|
||||
#define DSETID_REGDB 0x00000002 /* Regulatory Database */
|
||||
#define DSETID_POWER_CONTROL 0x00000003 /* TX Pwr Lim & Ant Gain */
|
||||
#define DSETID_USER_CONFIG 0x00000004 /* User Configuration */
|
||||
|
||||
#define DSETID_ANALOG_CONTROL_DATA_START 0x00000005
|
||||
#define DSETID_ANALOG_CONTROL_DATA_END 0x00000025
|
||||
/*
|
||||
* Get DSETID for various reference clock speeds.
|
||||
* For each speed there are three DataSets that correspond
|
||||
* to the three columns of bank6 data (addr, 11a, 11b/g).
|
||||
* This macro returns the dsetid of the first of those
|
||||
* three DataSets.
|
||||
*/
|
||||
#define ANALOG_CONTROL_DATA_DSETID(refclk) \
|
||||
(DSETID_ANALOG_CONTROL_DATA_START + 3*refclk)
|
||||
|
||||
/*
|
||||
* There are TWO STARTUP_PATCH DataSets.
|
||||
* DSETID_STARTUP_PATCH is historical, and was applied before BMI on
|
||||
* earlier systems. On AR6002, it is applied after BMI, just like
|
||||
* DSETID_STARTUP_PATCH2.
|
||||
*/
|
||||
#define DSETID_STARTUP_PATCH 0x00000026
|
||||
#define DSETID_GPIO_CONFIG_PATCH 0x00000027
|
||||
#define DSETID_WLANREGS 0x00000028 /* override wlan regs */
|
||||
#define DSETID_STARTUP_PATCH2 0x00000029
|
||||
|
||||
#define DSETID_WOW_CONFIG 0x00000090 /* WoW Configuration */
|
||||
|
||||
/* Add WHAL_INI_DATA_ID to DSETID_INI_DATA for a specific WHAL INI table. */
|
||||
#define DSETID_INI_DATA 0x00000100
|
||||
/* Reserved for WHAL INI Tables: 0x100..0x11f */
|
||||
#define DSETID_INI_DATA_END 0x0000011f
|
||||
|
||||
#define DSETID_VENDOR_START 0x00010000 /* Vendor-defined DataSets */
|
||||
|
||||
#define DSETID_INDEX_END 0xfffffffe /* Reserved to indicate the
|
||||
end of a memory-based
|
||||
DataSet Index */
|
||||
#define DSETID_INDEX_FREE 0xffffffff /* An unused index entry */
|
||||
|
||||
/*
|
||||
* PATCH DataSet format:
|
||||
* A list of patches, terminated by a patch with
|
||||
* address=PATCH_END.
|
||||
*
|
||||
* This allows for patches to be stored in flash.
|
||||
*/
|
||||
struct patch_s {
|
||||
A_UINT32 *address;
|
||||
A_UINT32 data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Skip some patches. Can be used to erase a single patch in a
|
||||
* patch DataSet without having to re-write the DataSet. May
|
||||
* also be used to embed information for use by subsequent
|
||||
* patch code. The "data" in a PATCH_SKIP tells how many
|
||||
* bytes of length "patch_s" to skip.
|
||||
*/
|
||||
#define PATCH_SKIP ((A_UINT32 *)0x00000000)
|
||||
|
||||
/*
|
||||
* Execute code at the address specified by "data".
|
||||
* The address of the patch structure is passed as
|
||||
* the one parameter.
|
||||
*/
|
||||
#define PATCH_CODE_ABS ((A_UINT32 *)0x00000001)
|
||||
|
||||
/*
|
||||
* Same as PATCH_CODE_ABS, but treat "data" as an
|
||||
* offset from the start of the patch word.
|
||||
*/
|
||||
#define PATCH_CODE_REL ((A_UINT32 *)0x00000002)
|
||||
|
||||
/* Mark the end of this patch DataSet. */
|
||||
#define PATCH_END ((A_UINT32 *)0xffffffff)
|
||||
|
||||
/*
|
||||
* A DataSet which contains a Binary Patch to some other DataSet
|
||||
* uses the original dsetid with the DSETID_BPATCH_FLAG bit set.
|
||||
* Such a BPatch DataSet consists of BPatch metadata followed by
|
||||
* the bdiff bytes. BPatch metadata consists of a single 32-bit
|
||||
* word that contains the size of the BPatched final image.
|
||||
*
|
||||
* To create a suitable bdiff DataSet, use bdiff in host/tools/bdiff
|
||||
* to create "diffs":
|
||||
* bdiff -q -O -nooldmd5 -nonewmd5 -d ORIGfile NEWfile diffs
|
||||
* Then add BPatch metadata to the start of "diffs".
|
||||
*
|
||||
* NB: There are some implementation-induced restrictions
|
||||
* on which DataSets can be BPatched.
|
||||
*/
|
||||
#define DSETID_BPATCH_FLAG 0x80000000
|
||||
|
||||
#endif /* __DSETID_H__ */
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(AR6001)
|
||||
#define GPIO_PIN_COUNT 18
|
||||
#else
|
||||
#define GPIO_PIN_COUNT 18
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Possible values for WMIX_GPIO_SET_REGISTER_CMDID.
|
||||
* NB: These match hardware order, so that addresses can
|
||||
* easily be computed.
|
||||
*/
|
||||
#define GPIO_ID_OUT 0x00000000
|
||||
#define GPIO_ID_OUT_W1TS 0x00000001
|
||||
#define GPIO_ID_OUT_W1TC 0x00000002
|
||||
#define GPIO_ID_ENABLE 0x00000003
|
||||
#define GPIO_ID_ENABLE_W1TS 0x00000004
|
||||
#define GPIO_ID_ENABLE_W1TC 0x00000005
|
||||
#define GPIO_ID_IN 0x00000006
|
||||
#define GPIO_ID_STATUS 0x00000007
|
||||
#define GPIO_ID_STATUS_W1TS 0x00000008
|
||||
#define GPIO_ID_STATUS_W1TC 0x00000009
|
||||
#define GPIO_ID_PIN0 0x0000000a
|
||||
#define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n))
|
||||
|
||||
#define GPIO_LAST_REGISTER_ID GPIO_ID_PIN(17)
|
||||
#define GPIO_ID_NONE 0xffffffff
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef _GPIO_API_H_
|
||||
#define _GPIO_API_H_
|
||||
/*
|
||||
* Copyright 2005 Atheros Communications, Inc., All Rights Reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Host-side General Purpose I/O API.
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/gpio_api.h#1 $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Send a command to the Target in order to change output on GPIO pins.
|
||||
*/
|
||||
A_STATUS wmi_gpio_output_set(struct wmi_t *wmip,
|
||||
A_UINT32 set_mask,
|
||||
A_UINT32 clear_mask,
|
||||
A_UINT32 enable_mask,
|
||||
A_UINT32 disable_mask);
|
||||
|
||||
/*
|
||||
* Send a command to the Target requesting input state of GPIO pins.
|
||||
*/
|
||||
A_STATUS wmi_gpio_input_get(struct wmi_t *wmip);
|
||||
|
||||
/*
|
||||
* Send a command to the Target to change the value of a GPIO register.
|
||||
*/
|
||||
A_STATUS wmi_gpio_register_set(struct wmi_t *wmip,
|
||||
A_UINT32 gpioreg_id,
|
||||
A_UINT32 value);
|
||||
|
||||
/*
|
||||
* Send a command to the Target to fetch the value of a GPIO register.
|
||||
*/
|
||||
A_STATUS wmi_gpio_register_get(struct wmi_t *wmip, A_UINT32 gpioreg_id);
|
||||
|
||||
/*
|
||||
* Send a command to the Target, acknowledging some GPIO interrupts.
|
||||
*/
|
||||
A_STATUS wmi_gpio_intr_ack(struct wmi_t *wmip, A_UINT32 ack_mask);
|
||||
|
||||
#endif /* _GPIO_API_H_ */
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
* HIF specific declarations and prototypes
|
||||
*/
|
||||
|
||||
#ifndef _HIF_H_
|
||||
#define _HIF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Header files */
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
|
||||
typedef struct htc_callbacks HTC_CALLBACKS;
|
||||
typedef struct hif_device HIF_DEVICE;
|
||||
|
||||
/*
|
||||
* direction - Direction of transfer (HIF_READ/HIF_WRITE).
|
||||
*/
|
||||
#define HIF_READ 0x00000001
|
||||
#define HIF_WRITE 0x00000002
|
||||
#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
|
||||
|
||||
/*
|
||||
* type - An interface may support different kind of read/write commands.
|
||||
* The command type is divided into a basic and an extended command
|
||||
* and can be specified using HIF_BASIC_IO/HIF_EXTENDED_IO.
|
||||
*/
|
||||
#define HIF_BASIC_IO 0x00000004
|
||||
#define HIF_EXTENDED_IO 0x00000008
|
||||
#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO)
|
||||
|
||||
/*
|
||||
* emode - This indicates the whether the command is to be executed in a
|
||||
* blocking or non-blocking fashion (HIF_SYNCHRONOUS/
|
||||
* HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
|
||||
* implemented using the asynchronous mode allowing the the bus
|
||||
* driver to indicate the completion of operation through the
|
||||
* registered callback routine. The requirement primarily comes
|
||||
* from the contexts these operations get called from (a driver's
|
||||
* transmit context or the ISR context in case of receive).
|
||||
* Support for both of these modes is essential.
|
||||
*/
|
||||
#define HIF_SYNCHRONOUS 0x00000010
|
||||
#define HIF_ASYNCHRONOUS 0x00000020
|
||||
#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
|
||||
|
||||
/*
|
||||
* dmode - An interface may support different kinds of commands based on
|
||||
* the tradeoff between the amount of data it can carry and the
|
||||
* setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
|
||||
* HIF_BLOCK_BASIS). In case of latter, the data is rounded off
|
||||
* to the nearest block size by padding. The size of the block is
|
||||
* configurable at compile time using the HIF_BLOCK_SIZE and is
|
||||
* negotiated with the target during initialization after the
|
||||
* dragon interrupts are enabled.
|
||||
*/
|
||||
#define HIF_BYTE_BASIS 0x00000040
|
||||
#define HIF_BLOCK_BASIS 0x00000080
|
||||
#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
|
||||
|
||||
/*
|
||||
* amode - This indicates if the address has to be incremented on dragon
|
||||
* after every read/write operation (HIF?FIXED_ADDRESS/
|
||||
* HIF_INCREMENTAL_ADDRESS).
|
||||
*/
|
||||
#define HIF_FIXED_ADDRESS 0x00000100
|
||||
#define HIF_INCREMENTAL_ADDRESS 0x00000200
|
||||
#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_ASYNC_BYTE_FIX \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
#define HIF_WR_ASYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_WR_ASYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_WR_SYNC_BYTE_FIX \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
#define HIF_WR_SYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_WR_SYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_RD_SYNC_BYTE_INC \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_RD_SYNC_BYTE_FIX \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
#define HIF_RD_ASYNC_BYTE_FIX \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
#define HIF_RD_ASYNC_BLOCK_FIX \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
|
||||
#define HIF_RD_ASYNC_BYTE_INC \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_RD_ASYNC_BLOCK_INC \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
#define HIF_RD_SYNC_BLOCK_INC \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
|
||||
typedef enum {
|
||||
HIF_DEVICE_POWER_STATE = 0,
|
||||
HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
|
||||
HIF_DEVICE_GET_MBOX_ADDR,
|
||||
HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
|
||||
HIF_DEVICE_GET_IRQ_PROC_MODE,
|
||||
HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
|
||||
} HIF_DEVICE_CONFIG_OPCODE;
|
||||
|
||||
/*
|
||||
* HIF CONFIGURE definitions:
|
||||
*
|
||||
* HIF_DEVICE_GET_MBOX_BLOCK_SIZE
|
||||
* input : none
|
||||
* output : array of 4 A_UINT32s
|
||||
* notes: block size is returned for each mailbox (4)
|
||||
*
|
||||
* HIF_DEVICE_GET_MBOX_ADDR
|
||||
* input : none
|
||||
* output : array of 4 A_UINT32
|
||||
* notes: address is returned for each mailbox (4) in the array
|
||||
*
|
||||
* HIF_DEVICE_GET_PENDING_EVENTS_FUNC
|
||||
* input : none
|
||||
* output: HIF_PENDING_EVENTS_FUNC function pointer
|
||||
* notes: this is optional for the HIF layer, if the request is
|
||||
* not handled then it indicates that the upper layer can use
|
||||
* the standard device methods to get pending events (IRQs, mailbox messages etc..)
|
||||
* otherwise it can call the function pointer to check pending events.
|
||||
*
|
||||
* HIF_DEVICE_GET_IRQ_PROC_MODE
|
||||
* input : none
|
||||
* output : HIF_DEVICE_IRQ_PROCESSING_MODE (interrupt processing mode)
|
||||
* note: the hif layer interfaces with the underlying OS-specific bus driver. The HIF
|
||||
* layer can report whether IRQ processing is requires synchronous behavior or
|
||||
* can be processed using asynchronous bus requests (typically faster).
|
||||
*
|
||||
* HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC
|
||||
* input :
|
||||
* output : HIF_MASK_UNMASK_RECV_EVENT function pointer
|
||||
* notes: this is optional for the HIF layer. The HIF layer may require a special mechanism
|
||||
* to mask receive message events. The upper layer can call this pointer when it needs
|
||||
* to mask/unmask receive events (in case it runs out of buffers).
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
HIF_DEVICE_IRQ_SYNC_ONLY, /* for HIF implementations that require the DSR to process all
|
||||
interrupts before returning */
|
||||
HIF_DEVICE_IRQ_ASYNC_SYNC, /* for HIF implementations that allow DSR to process interrupts
|
||||
using ASYNC I/O (that is HIFAckInterrupt can be called at a
|
||||
later time */
|
||||
} HIF_DEVICE_IRQ_PROCESSING_MODE;
|
||||
|
||||
#define HIF_MAX_DEVICES 1
|
||||
|
||||
struct htc_callbacks {
|
||||
A_UCHAR *name;
|
||||
A_UINT32 id;
|
||||
A_STATUS (* deviceInsertedHandler)(void *hif_handle);
|
||||
A_STATUS (* deviceRemovedHandler)(void *htc_handle, A_STATUS status);
|
||||
A_STATUS (* deviceSuspendHandler)(void *htc_handle);
|
||||
A_STATUS (* deviceResumeHandler)(void *htc_handle);
|
||||
A_STATUS (* deviceWakeupHandler)(void *htc_handle);
|
||||
A_STATUS (* rwCompletionHandler)(void *context, A_STATUS status);
|
||||
A_STATUS (* dsrHandler)(void *htc_handle);
|
||||
};
|
||||
|
||||
|
||||
#define HIF_OTHER_EVENTS (1 << 0) /* other interrupts (non-Recv) are pending, host
|
||||
needs to read the register table to figure out what */
|
||||
#define HIF_RECV_MSG_AVAIL (1 << 1) /* pending recv packet */
|
||||
|
||||
typedef struct _HIF_PENDING_EVENTS_INFO {
|
||||
A_UINT32 Events;
|
||||
A_UINT32 LookAhead;
|
||||
} HIF_PENDING_EVENTS_INFO;
|
||||
|
||||
/* function to get pending events , some HIF modules use special mechanisms
|
||||
* to detect packet available and other interrupts */
|
||||
typedef A_STATUS ( *HIF_PENDING_EVENTS_FUNC)(HIF_DEVICE *device,
|
||||
HIF_PENDING_EVENTS_INFO *pEvents,
|
||||
void *AsyncContext);
|
||||
|
||||
#define HIF_MASK_RECV TRUE
|
||||
#define HIF_UNMASK_RECV FALSE
|
||||
/* function to mask recv events */
|
||||
typedef A_STATUS ( *HIF_MASK_UNMASK_RECV_EVENT)(HIF_DEVICE *device,
|
||||
A_BOOL Mask,
|
||||
void *AsyncContext);
|
||||
|
||||
|
||||
/*
|
||||
* This API is used by the HTC layer to initialize the HIF layer and to
|
||||
* register different callback routines. Support for following events has
|
||||
* been captured - DSR, Read/Write completion, Device insertion/removal,
|
||||
* Device suspension/resumption/wakeup. In addition to this, the API is
|
||||
* also used to register the name and the revision of the chip. The latter
|
||||
* can be used to verify the revision of the chip read from the device
|
||||
* before reporting it to HTC.
|
||||
*/
|
||||
int HIFInit(HTC_CALLBACKS *callbacks);
|
||||
|
||||
/*
|
||||
* This API is used to provide the read/write interface over the specific bus
|
||||
* interface.
|
||||
* address - Starting address in the dragon's address space. For mailbox
|
||||
* writes, it refers to the start of the mbox boundary. It should
|
||||
* be ensured that the last byte falls on the mailbox's EOM. For
|
||||
* mailbox reads, it refers to the end of the mbox boundary.
|
||||
* buffer - Pointer to the buffer containg the data to be transmitted or
|
||||
* received.
|
||||
* length - Amount of data to be transmitted or received.
|
||||
* request - Characterizes the attributes of the command.
|
||||
*/
|
||||
A_STATUS
|
||||
HIFReadWrite(HIF_DEVICE *device,
|
||||
A_UINT32 address,
|
||||
A_UCHAR *buffer,
|
||||
A_UINT32 length,
|
||||
A_UINT32 request,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
* This can be initiated from the unload driver context ie when the HTCShutdown
|
||||
* routine is called.
|
||||
*/
|
||||
void HIFShutDownDevice(HIF_DEVICE *device);
|
||||
|
||||
/*
|
||||
* This should translate to an acknowledgment to the bus driver indicating that
|
||||
* the previous interrupt request has been serviced and the all the relevant
|
||||
* sources have been cleared. HTC is ready to process more interrupts.
|
||||
* This should prevent the bus driver from raising an interrupt unless the
|
||||
* previous one has been serviced and acknowledged using the previous API.
|
||||
*/
|
||||
void HIFAckInterrupt(HIF_DEVICE *device);
|
||||
|
||||
void HIFMaskInterrupt(HIF_DEVICE *device);
|
||||
|
||||
void HIFUnMaskInterrupt(HIF_DEVICE *device);
|
||||
|
||||
/*
|
||||
* This set of functions are to be used by the bus driver to notify
|
||||
* the HIF module about various events.
|
||||
* These are not implemented if the bus driver provides an alternative
|
||||
* way for this notification though callbacks for instance.
|
||||
*/
|
||||
int HIFInsertEventNotify(void);
|
||||
|
||||
int HIFRemoveEventNotify(void);
|
||||
|
||||
int HIFIRQEventNotify(void);
|
||||
|
||||
int HIFRWCompleteEventNotify(void);
|
||||
|
||||
/*
|
||||
* This function associates a opaque handle with the HIF layer
|
||||
* to be used in communication with upper layer i.e. HTC.
|
||||
* This would normaly be a pointer to htc_target data structure.
|
||||
*/
|
||||
void HIFSetHandle(void *hif_handle, void *handle);
|
||||
|
||||
A_STATUS
|
||||
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
|
||||
void *config, A_UINT32 configLen);
|
||||
|
||||
|
||||
struct device;
|
||||
struct device*
|
||||
HIFGetOSDevice(HIF_DEVICE *device);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HIF_H_ */
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _HOST_VERSION_H_
|
||||
#define _HOST_VERSION_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file contains version information for the sample host driver for the
|
||||
* AR6000 chip
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/host_version.h#2 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <AR6K_version.h>
|
||||
|
||||
/*
|
||||
* The version number is made up of major, minor, patch and build
|
||||
* numbers. These are 16 bit numbers. The build and release script will
|
||||
* set the build number using a Perforce counter. Here the build number is
|
||||
* set to 9999 so that builds done without the build-release script are easily
|
||||
* identifiable.
|
||||
*/
|
||||
|
||||
#define ATH_SW_VER_MAJOR __VER_MAJOR_
|
||||
#define ATH_SW_VER_MINOR __VER_MINOR_
|
||||
#define ATH_SW_VER_PATCH __VER_PATCH_
|
||||
#define ATH_SW_VER_BUILD 9999
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HOST_VERSION_H_ */
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __HTC_H__
|
||||
#define __HTC_H__
|
||||
|
||||
#ifndef ATH_TARGET
|
||||
#include "athstartpack.h"
|
||||
#endif
|
||||
|
||||
#define A_OFFSETOF(type,field) (int)(&(((type *)NULL)->field))
|
||||
|
||||
#define ASSEMBLE_UNALIGNED_UINT16(p,highbyte,lowbyte) \
|
||||
(((A_UINT16)(((A_UINT8 *)(p))[(highbyte)])) << 8 | (A_UINT16)(((A_UINT8 *)(p))[(lowbyte)]))
|
||||
|
||||
/* alignment independent macros (little-endian) to fetch UINT16s or UINT8s from a
|
||||
* structure using only the type and field name.
|
||||
* Use these macros if there is the potential for unaligned buffer accesses. */
|
||||
#define A_GET_UINT16_FIELD(p,type,field) \
|
||||
ASSEMBLE_UNALIGNED_UINT16(p,\
|
||||
A_OFFSETOF(type,field) + 1, \
|
||||
A_OFFSETOF(type,field))
|
||||
|
||||
#define A_SET_UINT16_FIELD(p,type,field,value) \
|
||||
{ \
|
||||
((A_UINT8 *)(p))[A_OFFSETOF(type,field)] = (A_UINT8)(value); \
|
||||
((A_UINT8 *)(p))[A_OFFSETOF(type,field) + 1] = (A_UINT8)((value) >> 8); \
|
||||
}
|
||||
|
||||
#define A_GET_UINT8_FIELD(p,type,field) \
|
||||
((A_UINT8 *)(p))[A_OFFSETOF(type,field)]
|
||||
|
||||
#define A_SET_UINT8_FIELD(p,type,field,value) \
|
||||
((A_UINT8 *)(p))[A_OFFSETOF(type,field)] = (value)
|
||||
|
||||
/****** DANGER DANGER ***************
|
||||
*
|
||||
* The frame header length and message formats defined herein were
|
||||
* selected to accommodate optimal alignment for target processing. This reduces code
|
||||
* size and improves performance.
|
||||
*
|
||||
* Any changes to the header length may alter the alignment and cause exceptions
|
||||
* on the target. When adding to the message structures insure that fields are
|
||||
* properly aligned.
|
||||
*
|
||||
*/
|
||||
|
||||
/* HTC frame header */
|
||||
typedef PREPACK struct _HTC_FRAME_HDR{
|
||||
/* do not remove or re-arrange these fields, these are minimally required
|
||||
* to take advantage of 4-byte lookaheads in some hardware implementations */
|
||||
A_UINT8 EndpointID;
|
||||
A_UINT8 Flags;
|
||||
A_UINT16 PayloadLen; /* length of data (including trailer) that follows the header */
|
||||
|
||||
/***** end of 4-byte lookahead ****/
|
||||
|
||||
A_UINT8 ControlBytes[2];
|
||||
|
||||
/* message payload starts after the header */
|
||||
|
||||
} POSTPACK HTC_FRAME_HDR;
|
||||
|
||||
/* frame header flags */
|
||||
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
|
||||
#define HTC_FLAGS_RECV_TRAILER (1 << 1)
|
||||
|
||||
|
||||
#define HTC_HDR_LENGTH (sizeof(HTC_FRAME_HDR))
|
||||
#define HTC_MAX_TRAILER_LENGTH 255
|
||||
#define HTC_MAX_PAYLOAD_LENGTH (2048 - sizeof(HTC_FRAME_HDR))
|
||||
|
||||
/* HTC control message IDs */
|
||||
typedef enum {
|
||||
HTC_MSG_READY_ID = 1,
|
||||
HTC_MSG_CONNECT_SERVICE_ID = 2,
|
||||
HTC_MSG_CONNECT_SERVICE_RESPONSE_ID = 3,
|
||||
HTC_MSG_SETUP_COMPLETE_ID = 4,
|
||||
} HTC_MSG_IDS;
|
||||
|
||||
#define HTC_MAX_CONTROL_MESSAGE_LENGTH 256
|
||||
|
||||
/* base message ID header */
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 MessageID;
|
||||
} POSTPACK HTC_UNKNOWN_MSG;
|
||||
|
||||
/* HTC ready message
|
||||
* direction : target-to-host */
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 MessageID; /* ID */
|
||||
A_UINT16 CreditCount; /* number of credits the target can offer */
|
||||
A_UINT16 CreditSize; /* size of each credit */
|
||||
A_UINT8 MaxEndpoints; /* maximum number of endpoints the target has resources for */
|
||||
A_UINT8 _Pad1;
|
||||
} POSTPACK HTC_READY_MSG;
|
||||
|
||||
#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
|
||||
|
||||
/* connect service
|
||||
* direction : host-to-target */
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 MessageID;
|
||||
A_UINT16 ServiceID; /* service ID of the service to connect to */
|
||||
A_UINT16 ConnectionFlags; /* connection flags */
|
||||
|
||||
#define HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE (1 << 2) /* reduce credit dribbling when
|
||||
the host needs credits */
|
||||
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK (0x3)
|
||||
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH 0x0
|
||||
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF 0x1
|
||||
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS 0x2
|
||||
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_UNITY 0x3
|
||||
|
||||
A_UINT8 ServiceMetaLength; /* length of meta data that follows */
|
||||
A_UINT8 _Pad1;
|
||||
|
||||
/* service-specific meta data starts after the header */
|
||||
|
||||
} POSTPACK HTC_CONNECT_SERVICE_MSG;
|
||||
|
||||
/* connect response
|
||||
* direction : target-to-host */
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 MessageID;
|
||||
A_UINT16 ServiceID; /* service ID that the connection request was made */
|
||||
A_UINT8 Status; /* service connection status */
|
||||
A_UINT8 EndpointID; /* assigned endpoint ID */
|
||||
A_UINT16 MaxMsgSize; /* maximum expected message size on this endpoint */
|
||||
A_UINT8 ServiceMetaLength; /* length of meta data that follows */
|
||||
A_UINT8 _Pad1;
|
||||
|
||||
/* service-specific meta data starts after the header */
|
||||
|
||||
} POSTPACK HTC_CONNECT_SERVICE_RESPONSE_MSG;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 MessageID;
|
||||
/* currently, no other fields */
|
||||
} POSTPACK HTC_SETUP_COMPLETE_MSG;
|
||||
|
||||
|
||||
/* connect response status codes */
|
||||
#define HTC_SERVICE_SUCCESS 0 /* success */
|
||||
#define HTC_SERVICE_NOT_FOUND 1 /* service could not be found */
|
||||
#define HTC_SERVICE_FAILED 2 /* specific service failed the connect */
|
||||
#define HTC_SERVICE_NO_RESOURCES 3 /* no resources (i.e. no more endpoints) */
|
||||
#define HTC_SERVICE_NO_MORE_EP 4 /* specific service is not allowing any more
|
||||
endpoints */
|
||||
|
||||
/* report record IDs */
|
||||
typedef enum {
|
||||
HTC_RECORD_NULL = 0,
|
||||
HTC_RECORD_CREDITS = 1,
|
||||
HTC_RECORD_LOOKAHEAD = 2,
|
||||
} HTC_RPT_IDS;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT8 RecordID; /* Record ID */
|
||||
A_UINT8 Length; /* Length of record */
|
||||
} POSTPACK HTC_RECORD_HDR;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT8 EndpointID; /* Endpoint that owns these credits */
|
||||
A_UINT8 Credits; /* credits to report since last report */
|
||||
} POSTPACK HTC_CREDIT_REPORT;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT8 PreValid; /* pre valid guard */
|
||||
A_UINT8 LookAhead[4]; /* 4 byte lookahead */
|
||||
A_UINT8 PostValid; /* post valid guard */
|
||||
|
||||
/* NOTE: the LookAhead array is guarded by a PreValid and Post Valid guard bytes.
|
||||
* The PreValid bytes must equal the inverse of the PostValid byte */
|
||||
|
||||
} POSTPACK HTC_LOOKAHEAD_REPORT;
|
||||
|
||||
#ifndef ATH_TARGET
|
||||
#include "athendpack.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __HTC_H__ */
|
||||
|
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HTC_API_H_
|
||||
#define _HTC_API_H_
|
||||
|
||||
#include <htc.h>
|
||||
#include <htc_services.h>
|
||||
#include "htc_packet.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* TODO.. for BMI */
|
||||
#define ENDPOINT1 0
|
||||
// TODO -remove me, but we have to fix BMI first
|
||||
#define HTC_MAILBOX_NUM_MAX 4
|
||||
|
||||
|
||||
/* ------ Endpoint IDS ------ */
|
||||
typedef enum
|
||||
{
|
||||
ENDPOINT_UNUSED = -1,
|
||||
ENDPOINT_0 = 0,
|
||||
ENDPOINT_1 = 1,
|
||||
ENDPOINT_2 = 2,
|
||||
ENDPOINT_3,
|
||||
ENDPOINT_4,
|
||||
ENDPOINT_5,
|
||||
ENDPOINT_6,
|
||||
ENDPOINT_7,
|
||||
ENDPOINT_8,
|
||||
ENDPOINT_MAX,
|
||||
} HTC_ENDPOINT_ID;
|
||||
|
||||
/* this is the amount of header room required by users of HTC */
|
||||
#define HTC_HEADER_LEN HTC_HDR_LENGTH
|
||||
|
||||
typedef void *HTC_HANDLE;
|
||||
|
||||
typedef A_UINT16 HTC_SERVICE_ID;
|
||||
|
||||
typedef struct _HTC_INIT_INFO {
|
||||
void (*AddInstance)(HTC_HANDLE);
|
||||
void (*DeleteInstance)(void *Instance);
|
||||
void (*TargetFailure)(void *Instance, A_STATUS Status);
|
||||
} HTC_INIT_INFO;
|
||||
|
||||
/* per service connection send completion */
|
||||
typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *,HTC_PACKET *);
|
||||
/* per service connection pkt received */
|
||||
typedef void (*HTC_EP_RECV_PKT)(void *,HTC_PACKET *);
|
||||
|
||||
/* Optional per service connection receive buffer re-fill callback,
|
||||
* On some OSes (like Linux) packets are allocated from a global pool and indicated up
|
||||
* to the network stack. The driver never gets the packets back from the OS. For these OSes
|
||||
* a refill callback can be used to allocate and re-queue buffers into HTC.
|
||||
*
|
||||
* On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and
|
||||
* the driver can re-queue these buffers into HTC. In this regard a refill callback is
|
||||
* unnecessary */
|
||||
typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint);
|
||||
|
||||
/* Optional per service connection callback when a send queue is full. This can occur if the
|
||||
* host continues queueing up TX packets faster than credits can arrive
|
||||
* To prevent the host (on some Oses like Linux) from continuously queueing packets
|
||||
* and consuming resources, this callback is provided so that that the host
|
||||
* can disable TX in the subsystem (i.e. network stack)
|
||||
* Other OSes require a "per-packet" indication_RAW_STREAM_NUM_MAX for each completed TX packet, this
|
||||
* closed loop mechanism will prevent the network stack from overunning the NIC */
|
||||
typedef void (*HTC_EP_SEND_QUEUE_FULL)(void *, HTC_ENDPOINT_ID Endpoint);
|
||||
/* Optional per service connection callback when a send queue is available for receive new packet. */
|
||||
typedef void (*HTC_EP_SEND_QUEUE_AVAIL)(void *, HTC_ENDPOINT_ID Endpoint);
|
||||
|
||||
typedef struct _HTC_EP_CALLBACKS {
|
||||
void *pContext; /* context for each callback */
|
||||
HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */
|
||||
HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */
|
||||
HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */
|
||||
HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */
|
||||
HTC_EP_SEND_QUEUE_AVAIL EpSendAvail; /* OPTIONAL send available callback */
|
||||
} HTC_EP_CALLBACKS;
|
||||
|
||||
/* service connection information */
|
||||
typedef struct _HTC_SERVICE_CONNECT_REQ {
|
||||
HTC_SERVICE_ID ServiceID; /* service ID to connect to */
|
||||
A_UINT16 ConnectionFlags; /* connection flags, see htc protocol definition */
|
||||
A_UINT8 *pMetaData; /* ptr to optional service-specific meta-data */
|
||||
A_UINT8 MetaDataLength; /* optional meta data length */
|
||||
HTC_EP_CALLBACKS EpCallbacks; /* endpoint callbacks */
|
||||
int MaxSendQueueDepth; /* maximum depth of any send queue */
|
||||
} HTC_SERVICE_CONNECT_REQ;
|
||||
|
||||
/* service connection response information */
|
||||
typedef struct _HTC_SERVICE_CONNECT_RESP {
|
||||
A_UINT8 *pMetaData; /* caller supplied buffer to optional meta-data */
|
||||
A_UINT8 BufferLength; /* length of caller supplied buffer */
|
||||
A_UINT8 ActualLength; /* actual length of meta data */
|
||||
HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */
|
||||
int MaxMsgLength; /* max length of all messages over this endpoint */
|
||||
A_UINT8 ConnectRespCode; /* connect response code from target */
|
||||
} HTC_SERVICE_CONNECT_RESP;
|
||||
|
||||
/* endpoint distribution structure */
|
||||
typedef struct _HTC_ENDPOINT_CREDIT_DIST {
|
||||
struct _HTC_ENDPOINT_CREDIT_DIST *pNext;
|
||||
struct _HTC_ENDPOINT_CREDIT_DIST *pPrev;
|
||||
HTC_SERVICE_ID ServiceID; /* Service ID (set by HTC) */
|
||||
HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */
|
||||
A_UINT32 DistFlags; /* distribution flags, distribution function can
|
||||
set default activity using SET_EP_ACTIVE() macro */
|
||||
int TxCreditsNorm; /* credits for normal operation, anything above this
|
||||
indicates the endpoint is over-subscribed, this field
|
||||
is only relevant to the credit distribution function */
|
||||
int TxCreditsMin; /* floor for credit distribution, this field is
|
||||
only relevant to the credit distribution function */
|
||||
int TxCreditsAssigned; /* number of credits assigned to this EP, this field
|
||||
is only relevant to the credit dist function */
|
||||
int TxCredits; /* current credits available, this field is used by
|
||||
HTC to determine whether a message can be sent or
|
||||
must be queued */
|
||||
int TxCreditsToDist; /* pending credits to distribute on this endpoint, this
|
||||
is set by HTC when credit reports arrive.
|
||||
The credit distribution functions sets this to zero
|
||||
when it distributes the credits */
|
||||
int TxCreditsSeek; /* this is the number of credits that the current pending TX
|
||||
packet needs to transmit. This is set by HTC when
|
||||
and endpoint needs credits in order to transmit */
|
||||
int TxCreditSize; /* size in bytes of each credit (set by HTC) */
|
||||
int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */
|
||||
void *pHTCReserved; /* reserved for HTC use */
|
||||
} HTC_ENDPOINT_CREDIT_DIST;
|
||||
|
||||
#define HTC_EP_ACTIVE (1 << 31)
|
||||
|
||||
/* macro to check if an endpoint has gone active, useful for credit
|
||||
* distributions */
|
||||
#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE)
|
||||
#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE
|
||||
|
||||
/* credit distibution code that is passed into the distrbution function,
|
||||
* there are mandatory and optional codes that must be handled */
|
||||
typedef enum _HTC_CREDIT_DIST_REASON {
|
||||
HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed
|
||||
send operations (MANDATORY) resulting in credit reports */
|
||||
HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */
|
||||
HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */
|
||||
HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by
|
||||
the distribution function */
|
||||
} HTC_CREDIT_DIST_REASON;
|
||||
|
||||
typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPList,
|
||||
HTC_CREDIT_DIST_REASON Reason);
|
||||
|
||||
typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPList,
|
||||
int TotalCredits);
|
||||
|
||||
/* endpoint statistics action */
|
||||
typedef enum _HTC_ENDPOINT_STAT_ACTION {
|
||||
HTC_EP_STAT_SAMPLE = 0, /* only read statistics */
|
||||
HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */
|
||||
HTC_EP_STAT_CLEAR /* clear only */
|
||||
} HTC_ENDPOINT_STAT_ACTION;
|
||||
|
||||
/* endpoint statistics */
|
||||
typedef struct _HTC_ENDPOINT_STATS {
|
||||
A_UINT32 TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on
|
||||
this endpoint */
|
||||
A_UINT32 TxIssued; /* running count of TX packets issued */
|
||||
A_UINT32 TxCreditRpts; /* running count of total credit reports received for this endpoint */
|
||||
A_UINT32 TxCreditRptsFromRx;
|
||||
A_UINT32 TxCreditRptsFromOther;
|
||||
A_UINT32 TxCreditRptsFromEp0;
|
||||
A_UINT32 TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */
|
||||
A_UINT32 TxCreditsFromOther; /* count of credits received via another endpoint */
|
||||
A_UINT32 TxCreditsFromEp0; /* count of credits received via another endpoint */
|
||||
A_UINT32 TxCreditsConsummed; /* count of consummed credits */
|
||||
A_UINT32 TxCreditsReturned; /* count of credits returned */
|
||||
A_UINT32 RxReceived; /* count of RX packets received */
|
||||
A_UINT32 RxLookAheads; /* count of lookahead records
|
||||
found in messages received on this endpoint */
|
||||
} HTC_ENDPOINT_STATS;
|
||||
|
||||
/* ------ Function Prototypes ------ */
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Initialize HTC
|
||||
@function name: HTCInit
|
||||
@input: pInfo - initialization information
|
||||
@output:
|
||||
@return: A_OK on success
|
||||
@notes: The caller initializes global HTC state and registers various instance
|
||||
notification callbacks (see HTC_INIT_INFO).
|
||||
|
||||
@example:
|
||||
@see also: HTCShutdown
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCInit(HTC_INIT_INFO *pInfo);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Get the underlying HIF device handle
|
||||
@function name: HTCGetHifDevice
|
||||
@input: HTCHandle - handle passed into the AddInstance callback
|
||||
@output:
|
||||
@return: opaque HIF device handle usable in HIF API calls.
|
||||
@notes:
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void *HTCGetHifDevice(HTC_HANDLE HTCHandle);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Set the associated instance for the HTC handle
|
||||
@function name: HTCSetInstance
|
||||
@input: HTCHandle - handle passed into the AddInstance callback
|
||||
Instance - caller supplied instance object
|
||||
@output:
|
||||
@return:
|
||||
@notes: Caller must set the instance information for the HTC handle in order to receive
|
||||
notifications for instance deletion (DeleteInstance callback is called) and for target
|
||||
failure notification.
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Set credit distribution parameters
|
||||
@function name: HTCSetCreditDistribution
|
||||
@input: HTCHandle - HTC handle
|
||||
pCreditDistCont - caller supplied context to pass into distribution functions
|
||||
CreditDistFunc - Distribution function callback
|
||||
CreditDistInit - Credit Distribution initialization callback
|
||||
ServicePriorityOrder - Array containing list of service IDs, lowest index is highest
|
||||
priority
|
||||
ListLength - number of elements in ServicePriorityOrder
|
||||
@output:
|
||||
@return:
|
||||
@notes: The user can set a custom credit distribution function to handle special requirements
|
||||
for each endpoint. A default credit distribution routine can be used by setting
|
||||
CreditInitFunc to NULL. The default credit distribution is only provided for simple
|
||||
"fair" credit distribution without regard to any prioritization.
|
||||
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
|
||||
void *pCreditDistContext,
|
||||
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
|
||||
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
|
||||
HTC_SERVICE_ID ServicePriorityOrder[],
|
||||
int ListLength);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Wait for the target to indicate the HTC layer is ready
|
||||
@function name: HTCWaitTarget
|
||||
@input: HTCHandle - HTC handle
|
||||
@output:
|
||||
@return:
|
||||
@notes: This API blocks until the target responds with an HTC ready message.
|
||||
The caller should not connect services until the target has indicated it is
|
||||
ready.
|
||||
@example:
|
||||
@see also: HTCConnectService
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Start target service communications
|
||||
@function name: HTCStart
|
||||
@input: HTCHandle - HTC handle
|
||||
@output:
|
||||
@return:
|
||||
@notes: This API indicates to the target that the service connection phase is complete
|
||||
and the target can freely start all connected services. This API should only be
|
||||
called AFTER all service connections have been made. TCStart will issue a
|
||||
SETUP_COMPLETE message to the target to indicate that all service connections
|
||||
have been made and the target can start communicating over the endpoints.
|
||||
@example:
|
||||
@see also: HTCConnectService
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCStart(HTC_HANDLE HTCHandle);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Add receive packet to HTC
|
||||
@function name: HTCAddReceivePkt
|
||||
@input: HTCHandle - HTC handle
|
||||
pPacket - HTC receive packet to add
|
||||
@output:
|
||||
@return: A_OK on success
|
||||
@notes: user must supply HTC packets for capturing incomming HTC frames. The caller
|
||||
must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
|
||||
macro.
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Connect to an HTC service
|
||||
@function name: HTCConnectService
|
||||
@input: HTCHandle - HTC handle
|
||||
pReq - connection details
|
||||
@output: pResp - connection response
|
||||
@return:
|
||||
@notes: Service connections must be performed before HTCStart. User provides callback handlers
|
||||
for various endpoint events.
|
||||
@example:
|
||||
@see also: HTCStart
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
|
||||
HTC_SERVICE_CONNECT_REQ *pReq,
|
||||
HTC_SERVICE_CONNECT_RESP *pResp);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Send an HTC packet
|
||||
@function name: HTCSendPkt
|
||||
@input: HTCHandle - HTC handle
|
||||
pPacket - packet to send
|
||||
@output:
|
||||
@return: A_OK
|
||||
@notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro.
|
||||
This interface is fully asynchronous. On error, HTC SendPkt will
|
||||
call the registered Endpoint callback to cleanup the packet.
|
||||
@example:
|
||||
@see also: HTCFlushEndpoint
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Stop HTC service communications
|
||||
@function name: HTCStop
|
||||
@input: HTCHandle - HTC handle
|
||||
@output:
|
||||
@return:
|
||||
@notes: HTC communications is halted. All receive and pending TX packets will
|
||||
be flushed.
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCStop(HTC_HANDLE HTCHandle);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Shutdown HTC
|
||||
@function name: HTCShutdown
|
||||
@input:
|
||||
@output:
|
||||
@return:
|
||||
@notes: This cleans up all resources allocated by HTCInit().
|
||||
@example:
|
||||
@see also: HTCInit
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCShutDown(void);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Flush pending TX packets
|
||||
@function name: HTCFlushEndpoint
|
||||
@input: HTCHandle - HTC handle
|
||||
Endpoint - Endpoint to flush
|
||||
Tag - flush tag
|
||||
@output:
|
||||
@return:
|
||||
@notes: The Tag parameter is used to selectively flush packets with matching tags.
|
||||
The value of 0 forces all packets to be flush regardless of tag.
|
||||
@example:
|
||||
@see also: HTCSendPkt
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Dump credit distribution state
|
||||
@function name: HTCDumpCreditStates
|
||||
@input: HTCHandle - HTC handle
|
||||
@output:
|
||||
@return:
|
||||
@notes: This dumps all credit distribution information to the debugger
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCDumpCreditStates(HTC_HANDLE HTCHandle);
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Indicate a traffic activity change on an endpoint
|
||||
@function name: HTCIndicateActivityChange
|
||||
@input: HTCHandle - HTC handle
|
||||
Endpoint - endpoint in which activity has changed
|
||||
Active - TRUE if active, FALSE if it has become inactive
|
||||
@output:
|
||||
@return:
|
||||
@notes: This triggers the registered credit distribution function to
|
||||
re-adjust credits for active/inactive endpoints.
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
|
||||
HTC_ENDPOINT_ID Endpoint,
|
||||
A_BOOL Active);
|
||||
|
||||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@desc: Get endpoint statistics
|
||||
@function name: HTCGetEndpointStatistics
|
||||
@input: HTCHandle - HTC handle
|
||||
Endpoint - Endpoint identifier
|
||||
Action - action to take with statistics
|
||||
@output:
|
||||
pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR)
|
||||
|
||||
@return: TRUE if statistics profiling is enabled, otherwise FALSE.
|
||||
|
||||
@notes: Statistics is a compile-time option and this function may return FALSE
|
||||
if HTC is not compiled with profiling.
|
||||
|
||||
The caller can specify the statistic "action" to take when sampling
|
||||
the statistics. This includes:
|
||||
|
||||
HTC_EP_STAT_SAMPLE: The pStats structure is filled with the current values.
|
||||
HTC_EP_STAT_SAMPLE_AND_CLEAR: The structure is filled and the current statistics
|
||||
are cleared.
|
||||
HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL value for
|
||||
pStats
|
||||
|
||||
@example:
|
||||
@see also:
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
|
||||
HTC_ENDPOINT_ID Endpoint,
|
||||
HTC_ENDPOINT_STAT_ACTION Action,
|
||||
HTC_ENDPOINT_STATS *pStats);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HTC_API_H_ */
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HTC_PACKET_H_
|
||||
#define HTC_PACKET_H_
|
||||
|
||||
|
||||
#include "dl_list.h"
|
||||
|
||||
struct _HTC_PACKET;
|
||||
|
||||
typedef void (* HTC_PACKET_COMPLETION)(void *,struct _HTC_PACKET *);
|
||||
|
||||
typedef A_UINT16 HTC_TX_TAG;
|
||||
|
||||
typedef struct _HTC_TX_PACKET_INFO {
|
||||
HTC_TX_TAG Tag; /* tag used to selective flush packets */
|
||||
} HTC_TX_PACKET_INFO;
|
||||
|
||||
#define HTC_TX_PACKET_TAG_ALL 0 /* a tag of zero is reserved and used to flush ALL packets */
|
||||
#define HTC_TX_PACKET_TAG_INTERNAL 1 /* internal tags start here */
|
||||
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) /* user-defined tags start here */
|
||||
|
||||
typedef struct _HTC_RX_PACKET_INFO {
|
||||
A_UINT32 Unused; /* for future use and to make compilers happy */
|
||||
} HTC_RX_PACKET_INFO;
|
||||
|
||||
/* wrapper around endpoint-specific packets */
|
||||
typedef struct _HTC_PACKET {
|
||||
DL_LIST ListLink; /* double link */
|
||||
void *pPktContext; /* caller's per packet specific context */
|
||||
|
||||
A_UINT8 *pBufferStart; /* the true buffer start , the caller can
|
||||
store the real buffer start here. In
|
||||
receive callbacks, the HTC layer sets pBuffer
|
||||
to the start of the payload past the header. This
|
||||
field allows the caller to reset pBuffer when it
|
||||
recycles receive packets back to HTC */
|
||||
/*
|
||||
* Pointer to the start of the buffer. In the transmit
|
||||
* direction this points to the start of the payload. In the
|
||||
* receive direction, however, the buffer when queued up
|
||||
* points to the start of the HTC header but when returned
|
||||
* to the caller points to the start of the payload
|
||||
*/
|
||||
A_UINT8 *pBuffer; /* payload start (RX/TX) */
|
||||
A_UINT32 BufferLength; /* length of buffer */
|
||||
A_UINT32 ActualLength; /* actual length of payload */
|
||||
int Endpoint; /* endpoint that this packet was sent/recv'd from */
|
||||
A_STATUS Status; /* completion status */
|
||||
union {
|
||||
HTC_TX_PACKET_INFO AsTx; /* Tx Packet specific info */
|
||||
HTC_RX_PACKET_INFO AsRx; /* Rx Packet specific info */
|
||||
} PktInfo;
|
||||
|
||||
/* the following fields are for internal HTC use */
|
||||
HTC_PACKET_COMPLETION Completion; /* completion */
|
||||
void *pContext; /* HTC private completion context */
|
||||
A_UINT32 HTCReserved; /* reserved */
|
||||
} HTC_PACKET;
|
||||
|
||||
|
||||
|
||||
#define COMPLETE_HTC_PACKET(p,status) \
|
||||
{ \
|
||||
(p)->Status = (status); \
|
||||
(p)->Completion((p)->pContext,(p)); \
|
||||
}
|
||||
|
||||
#define INIT_HTC_PACKET_INFO(p,b,len) \
|
||||
{ \
|
||||
(p)->pBufferStart = (b); \
|
||||
(p)->BufferLength = (len); \
|
||||
}
|
||||
|
||||
/* macro to set an initial RX packet for refilling HTC */
|
||||
#define SET_HTC_PACKET_INFO_RX_REFILL(p,c,b,len,ep) \
|
||||
{ \
|
||||
(p)->pPktContext = (c); \
|
||||
(p)->pBuffer = (b); \
|
||||
(p)->pBufferStart = (b); \
|
||||
(p)->BufferLength = (len); \
|
||||
(p)->Endpoint = (ep); \
|
||||
}
|
||||
|
||||
/* fast macro to recycle an RX packet that will be re-queued to HTC */
|
||||
#define HTC_PACKET_RESET_RX(p) \
|
||||
(p)->pBuffer = (p)->pBufferStart
|
||||
|
||||
/* macro to set packet parameters for TX */
|
||||
#define SET_HTC_PACKET_INFO_TX(p,c,b,len,ep,tag) \
|
||||
{ \
|
||||
(p)->pPktContext = (c); \
|
||||
(p)->pBuffer = (b); \
|
||||
(p)->ActualLength = (len); \
|
||||
(p)->Endpoint = (ep); \
|
||||
(p)->PktInfo.AsTx.Tag = (tag); \
|
||||
}
|
||||
|
||||
/* HTC Packet Queueing Macros */
|
||||
typedef DL_LIST HTC_PACKET_QUEUE;
|
||||
/* initialize queue */
|
||||
#define INIT_HTC_PACKET_QUEUE(pQ) DL_LIST_INIT((pQ))
|
||||
/* enqueue HTC packet to the tail of the queue */
|
||||
#define HTC_PACKET_ENQUEUE(pQ,p) DL_ListInsertTail((pQ),&(p)->ListLink)
|
||||
/* test if a queue is empty */
|
||||
#define HTC_QUEUE_EMPTY(pQ) DL_LIST_IS_EMPTY((pQ))
|
||||
/* get packet at head without removing it */
|
||||
#define HTC_GET_PKT_AT_HEAD(pQ) A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(pQ)),HTC_PACKET,ListLink);
|
||||
/* remove a packet from the current list it is linked to */
|
||||
#define HTC_PACKET_REMOVE(p) DL_ListRemove(&(p)->ListLink)
|
||||
|
||||
/* dequeue an HTC packet from the head of the queue */
|
||||
static INLINE HTC_PACKET *HTC_PACKET_DEQUEUE(HTC_PACKET_QUEUE *queue) {
|
||||
DL_LIST *pItem = DL_ListRemoveItemFromHead(queue);
|
||||
if (pItem != NULL) {
|
||||
return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /*HTC_PACKET_H_*/
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HTC_SERVICES_H__
|
||||
#define __HTC_SERVICES_H__
|
||||
|
||||
/* Current service IDs */
|
||||
|
||||
typedef enum {
|
||||
RSVD_SERVICE_GROUP = 0,
|
||||
WMI_SERVICE_GROUP = 1,
|
||||
|
||||
HTC_TEST_GROUP = 254,
|
||||
HTC_SERVICE_GROUP_LAST = 255
|
||||
}HTC_SERVICE_GROUP_IDS;
|
||||
|
||||
#define MAKE_SERVICE_ID(group,index) \
|
||||
(int)(((int)group << 8) | (int)(index))
|
||||
|
||||
/* NOTE: service ID of 0x0000 is reserved and should never be used */
|
||||
#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP,1)
|
||||
#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,0)
|
||||
#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,1)
|
||||
#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,2)
|
||||
#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,3)
|
||||
#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,4)
|
||||
#define WMI_MAX_SERVICES 5
|
||||
|
||||
/* raw stream service (i.e. flash, tcmd, calibration apps) */
|
||||
#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0)
|
||||
|
||||
#endif /*HTC_SERVICES_H_*/
|
|
@ -0,0 +1,342 @@
|
|||
/*-
|
||||
* Copyright (c) 2001 Atsushi Onoe
|
||||
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
|
||||
* Copyright (c) 2006 Atheros Communications, Inc.
|
||||
*
|
||||
* Wireless Network driver for Atheros AR6001
|
||||
* All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef _NET80211_IEEE80211_H_
|
||||
#define _NET80211_IEEE80211_H_
|
||||
|
||||
#include "athstartpack.h"
|
||||
|
||||
/*
|
||||
* 802.11 protocol definitions.
|
||||
*/
|
||||
|
||||
#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
|
||||
/* is 802.11 address multicast/broadcast? */
|
||||
#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01)
|
||||
#define IEEE80211_ADDR_EQ(addr1, addr2) \
|
||||
(A_MEMCMP(addr1, addr2, IEEE80211_ADDR_LEN) == 0)
|
||||
|
||||
#define IEEE80211_KEYBUF_SIZE 16
|
||||
#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx and rx */
|
||||
|
||||
/*
|
||||
* NB: these values are ordered carefully; there are lots of
|
||||
* of implications in any reordering. In particular beware
|
||||
* that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY.
|
||||
*/
|
||||
#define IEEE80211_CIPHER_WEP 0
|
||||
#define IEEE80211_CIPHER_TKIP 1
|
||||
#define IEEE80211_CIPHER_AES_OCB 2
|
||||
#define IEEE80211_CIPHER_AES_CCM 3
|
||||
#define IEEE80211_CIPHER_CKIP 5
|
||||
#define IEEE80211_CIPHER_CCKM_KRK 6
|
||||
#define IEEE80211_CIPHER_NONE 7 /* pseudo value */
|
||||
|
||||
#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1)
|
||||
|
||||
#define IEEE80211_IS_VALID_WEP_CIPHER_LEN(len) \
|
||||
(((len) == 5) || ((len) == 13) || ((len) == 16))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* generic definitions for IEEE 802.11 frames
|
||||
*/
|
||||
PREPACK struct ieee80211_frame {
|
||||
A_UINT8 i_fc[2];
|
||||
A_UINT8 i_dur[2];
|
||||
A_UINT8 i_addr1[IEEE80211_ADDR_LEN];
|
||||
A_UINT8 i_addr2[IEEE80211_ADDR_LEN];
|
||||
A_UINT8 i_addr3[IEEE80211_ADDR_LEN];
|
||||
A_UINT8 i_seq[2];
|
||||
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
|
||||
/* see below */
|
||||
} POSTPACK;
|
||||
|
||||
#define IEEE80211_FC0_VERSION_MASK 0x03
|
||||
#define IEEE80211_FC0_VERSION_SHIFT 0
|
||||
#define IEEE80211_FC0_VERSION_0 0x00
|
||||
#define IEEE80211_FC0_TYPE_MASK 0x0c
|
||||
#define IEEE80211_FC0_TYPE_SHIFT 2
|
||||
#define IEEE80211_FC0_TYPE_MGT 0x00
|
||||
#define IEEE80211_FC0_TYPE_CTL 0x04
|
||||
#define IEEE80211_FC0_TYPE_DATA 0x08
|
||||
|
||||
#define IEEE80211_FC0_SUBTYPE_MASK 0xf0
|
||||
#define IEEE80211_FC0_SUBTYPE_SHIFT 4
|
||||
/* for TYPE_MGT */
|
||||
#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00
|
||||
#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10
|
||||
#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20
|
||||
#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30
|
||||
#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40
|
||||
#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50
|
||||
#define IEEE80211_FC0_SUBTYPE_BEACON 0x80
|
||||
#define IEEE80211_FC0_SUBTYPE_ATIM 0x90
|
||||
#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0
|
||||
#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0
|
||||
#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0
|
||||
/* for TYPE_CTL */
|
||||
#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0
|
||||
#define IEEE80211_FC0_SUBTYPE_RTS 0xb0
|
||||
#define IEEE80211_FC0_SUBTYPE_CTS 0xc0
|
||||
#define IEEE80211_FC0_SUBTYPE_ACK 0xd0
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0
|
||||
/* for TYPE_DATA (bit combination) */
|
||||
#define IEEE80211_FC0_SUBTYPE_DATA 0x00
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30
|
||||
#define IEEE80211_FC0_SUBTYPE_NODATA 0x40
|
||||
#define IEEE80211_FC0_SUBTYPE_CFACK 0x50
|
||||
#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60
|
||||
#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70
|
||||
#define IEEE80211_FC0_SUBTYPE_QOS 0x80
|
||||
#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0
|
||||
|
||||
#define IEEE80211_FC1_DIR_MASK 0x03
|
||||
#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
|
||||
#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */
|
||||
#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */
|
||||
#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */
|
||||
|
||||
#define IEEE80211_FC1_MORE_FRAG 0x04
|
||||
#define IEEE80211_FC1_RETRY 0x08
|
||||
#define IEEE80211_FC1_PWR_MGT 0x10
|
||||
#define IEEE80211_FC1_MORE_DATA 0x20
|
||||
#define IEEE80211_FC1_WEP 0x40
|
||||
#define IEEE80211_FC1_ORDER 0x80
|
||||
|
||||
#define IEEE80211_SEQ_FRAG_MASK 0x000f
|
||||
#define IEEE80211_SEQ_FRAG_SHIFT 0
|
||||
#define IEEE80211_SEQ_SEQ_MASK 0xfff0
|
||||
#define IEEE80211_SEQ_SEQ_SHIFT 4
|
||||
|
||||
#define IEEE80211_NWID_LEN 32
|
||||
|
||||
/*
|
||||
* 802.11 rate set.
|
||||
*/
|
||||
#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
|
||||
#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
|
||||
|
||||
#define WMM_NUM_AC 4 /* 4 AC categories */
|
||||
|
||||
#define WMM_PARAM_ACI_M 0x60 /* Mask for ACI field */
|
||||
#define WMM_PARAM_ACI_S 5 /* Shift for ACI field */
|
||||
#define WMM_PARAM_ACM_M 0x10 /* Mask for ACM bit */
|
||||
#define WMM_PARAM_ACM_S 4 /* Shift for ACM bit */
|
||||
#define WMM_PARAM_AIFSN_M 0x0f /* Mask for aifsn field */
|
||||
#define WMM_PARAM_LOGCWMIN_M 0x0f /* Mask for CwMin field (in log) */
|
||||
#define WMM_PARAM_LOGCWMAX_M 0xf0 /* Mask for CwMax field (in log) */
|
||||
#define WMM_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */
|
||||
|
||||
#define WMM_AC_TO_TID(_ac) ( \
|
||||
((_ac) == WMM_AC_VO) ? 6 : \
|
||||
((_ac) == WMM_AC_VI) ? 5 : \
|
||||
((_ac) == WMM_AC_BK) ? 1 : \
|
||||
0)
|
||||
|
||||
#define TID_TO_WMM_AC(_tid) ( \
|
||||
((_tid) < 1) ? WMM_AC_BE : \
|
||||
((_tid) < 3) ? WMM_AC_BK : \
|
||||
((_tid) < 6) ? WMM_AC_VI : \
|
||||
WMM_AC_VO)
|
||||
/*
|
||||
* Management information element payloads.
|
||||
*/
|
||||
|
||||
enum {
|
||||
IEEE80211_ELEMID_SSID = 0,
|
||||
IEEE80211_ELEMID_RATES = 1,
|
||||
IEEE80211_ELEMID_FHPARMS = 2,
|
||||
IEEE80211_ELEMID_DSPARMS = 3,
|
||||
IEEE80211_ELEMID_CFPARMS = 4,
|
||||
IEEE80211_ELEMID_TIM = 5,
|
||||
IEEE80211_ELEMID_IBSSPARMS = 6,
|
||||
IEEE80211_ELEMID_COUNTRY = 7,
|
||||
IEEE80211_ELEMID_CHALLENGE = 16,
|
||||
/* 17-31 reserved for challenge text extension */
|
||||
IEEE80211_ELEMID_PWRCNSTR = 32,
|
||||
IEEE80211_ELEMID_PWRCAP = 33,
|
||||
IEEE80211_ELEMID_TPCREQ = 34,
|
||||
IEEE80211_ELEMID_TPCREP = 35,
|
||||
IEEE80211_ELEMID_SUPPCHAN = 36,
|
||||
IEEE80211_ELEMID_CHANSWITCH = 37,
|
||||
IEEE80211_ELEMID_MEASREQ = 38,
|
||||
IEEE80211_ELEMID_MEASREP = 39,
|
||||
IEEE80211_ELEMID_QUIET = 40,
|
||||
IEEE80211_ELEMID_IBSSDFS = 41,
|
||||
IEEE80211_ELEMID_ERP = 42,
|
||||
IEEE80211_ELEMID_RSN = 48,
|
||||
IEEE80211_ELEMID_XRATES = 50,
|
||||
IEEE80211_ELEMID_TPC = 150,
|
||||
IEEE80211_ELEMID_CCKM = 156,
|
||||
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
|
||||
};
|
||||
|
||||
#define ATH_OUI 0x7f0300 /* Atheros OUI */
|
||||
#define ATH_OUI_TYPE 0x01
|
||||
#define ATH_OUI_SUBTYPE 0x01
|
||||
#define ATH_OUI_VERSION 0x00
|
||||
|
||||
#define WPA_OUI 0xf25000
|
||||
#define WPA_OUI_TYPE 0x01
|
||||
#define WPA_VERSION 1 /* current supported version */
|
||||
|
||||
#define WPA_CSE_NULL 0x00
|
||||
#define WPA_CSE_WEP40 0x01
|
||||
#define WPA_CSE_TKIP 0x02
|
||||
#define WPA_CSE_CCMP 0x04
|
||||
#define WPA_CSE_WEP104 0x05
|
||||
|
||||
#define WPA_ASE_NONE 0x00
|
||||
#define WPA_ASE_8021X_UNSPEC 0x01
|
||||
#define WPA_ASE_8021X_PSK 0x02
|
||||
|
||||
#define RSN_OUI 0xac0f00
|
||||
#define RSN_VERSION 1 /* current supported version */
|
||||
|
||||
#define RSN_CSE_NULL 0x00
|
||||
#define RSN_CSE_WEP40 0x01
|
||||
#define RSN_CSE_TKIP 0x02
|
||||
#define RSN_CSE_WRAP 0x03
|
||||
#define RSN_CSE_CCMP 0x04
|
||||
#define RSN_CSE_WEP104 0x05
|
||||
|
||||
#define RSN_ASE_NONE 0x00
|
||||
#define RSN_ASE_8021X_UNSPEC 0x01
|
||||
#define RSN_ASE_8021X_PSK 0x02
|
||||
|
||||
#define RSN_CAP_PREAUTH 0x01
|
||||
|
||||
#define WMM_OUI 0xf25000
|
||||
#define WMM_OUI_TYPE 0x02
|
||||
#define WMM_INFO_OUI_SUBTYPE 0x00
|
||||
#define WMM_PARAM_OUI_SUBTYPE 0x01
|
||||
#define WMM_VERSION 1
|
||||
|
||||
/* WMM stream classes */
|
||||
#define WMM_NUM_AC 4
|
||||
#define WMM_AC_BE 0 /* best effort */
|
||||
#define WMM_AC_BK 1 /* background */
|
||||
#define WMM_AC_VI 2 /* video */
|
||||
#define WMM_AC_VO 3 /* voice */
|
||||
|
||||
/* TSPEC related */
|
||||
#define ACTION_CATEGORY_CODE_TSPEC 17
|
||||
#define ACTION_CODE_TSPEC_ADDTS 0
|
||||
#define ACTION_CODE_TSPEC_ADDTS_RESP 1
|
||||
#define ACTION_CODE_TSPEC_DELTS 2
|
||||
|
||||
typedef enum {
|
||||
TSPEC_STATUS_CODE_ADMISSION_ACCEPTED = 0,
|
||||
TSPEC_STATUS_CODE_ADDTS_INVALID_PARAMS = 0x1,
|
||||
TSPEC_STATUS_CODE_ADDTS_REQUEST_REFUSED = 0x3,
|
||||
TSPEC_STATUS_CODE_UNSPECIFIED_QOS_RELATED_FAILURE = 0xC8,
|
||||
TSPEC_STATUS_CODE_REQUESTED_REFUSED_POLICY_CONFIGURATION = 0xC9,
|
||||
TSPEC_STATUS_CODE_INSUFFCIENT_BANDWIDTH = 0xCA,
|
||||
TSPEC_STATUS_CODE_INVALID_PARAMS = 0xCB,
|
||||
TSPEC_STATUS_CODE_DELTS_SENT = 0x30,
|
||||
TSPEC_STATUS_CODE_DELTS_RECV = 0x31,
|
||||
} TSPEC_STATUS_CODE;
|
||||
|
||||
/*
|
||||
* WMM/802.11e Tspec Element
|
||||
*/
|
||||
typedef PREPACK struct wmm_tspec_ie_t {
|
||||
A_UINT8 elementId;
|
||||
A_UINT8 len;
|
||||
A_UINT8 oui[3];
|
||||
A_UINT8 ouiType;
|
||||
A_UINT8 ouiSubType;
|
||||
A_UINT8 version;
|
||||
A_UINT16 tsInfo_info;
|
||||
A_UINT8 tsInfo_reserved;
|
||||
A_UINT16 nominalMSDU;
|
||||
A_UINT16 maxMSDU;
|
||||
A_UINT32 minServiceInt;
|
||||
A_UINT32 maxServiceInt;
|
||||
A_UINT32 inactivityInt;
|
||||
A_UINT32 suspensionInt;
|
||||
A_UINT32 serviceStartTime;
|
||||
A_UINT32 minDataRate;
|
||||
A_UINT32 meanDataRate;
|
||||
A_UINT32 peakDataRate;
|
||||
A_UINT32 maxBurstSize;
|
||||
A_UINT32 delayBound;
|
||||
A_UINT32 minPhyRate;
|
||||
A_UINT16 sba;
|
||||
A_UINT16 mediumTime;
|
||||
} POSTPACK WMM_TSPEC_IE;
|
||||
|
||||
|
||||
/*
|
||||
* BEACON management packets
|
||||
*
|
||||
* octet timestamp[8]
|
||||
* octet beacon interval[2]
|
||||
* octet capability information[2]
|
||||
* information element
|
||||
* octet elemid
|
||||
* octet length
|
||||
* octet information[length]
|
||||
*/
|
||||
|
||||
#define IEEE80211_BEACON_INTERVAL(beacon) \
|
||||
((beacon)[8] | ((beacon)[9] << 8))
|
||||
#define IEEE80211_BEACON_CAPABILITY(beacon) \
|
||||
((beacon)[10] | ((beacon)[11] << 8))
|
||||
|
||||
#define IEEE80211_CAPINFO_ESS 0x0001
|
||||
#define IEEE80211_CAPINFO_IBSS 0x0002
|
||||
#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004
|
||||
#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008
|
||||
#define IEEE80211_CAPINFO_PRIVACY 0x0010
|
||||
#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020
|
||||
#define IEEE80211_CAPINFO_PBCC 0x0040
|
||||
#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080
|
||||
/* bits 8-9 are reserved */
|
||||
#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400
|
||||
#define IEEE80211_CAPINFO_APSD 0x0800
|
||||
/* bit 12 is reserved */
|
||||
#define IEEE80211_CAPINFO_DSSSOFDM 0x2000
|
||||
/* bits 14-15 are reserved */
|
||||
|
||||
/*
|
||||
* Authentication Modes
|
||||
*/
|
||||
|
||||
enum ieee80211_authmode {
|
||||
IEEE80211_AUTH_NONE = 0,
|
||||
IEEE80211_AUTH_OPEN = 1,
|
||||
IEEE80211_AUTH_SHARED = 2,
|
||||
IEEE80211_AUTH_8021X = 3,
|
||||
IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
|
||||
/* NB: these are used only for ioctls */
|
||||
IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x */
|
||||
IEEE80211_AUTH_WPA_PSK = 6, /* WPA/RSN w/ PSK */
|
||||
IEEE80211_AUTH_WPA_CCKM = 7, /* WPA/RSN IE w/ CCKM */
|
||||
};
|
||||
|
||||
#include "athendpack.h"
|
||||
|
||||
#endif /* _NET80211_IEEE80211_H_ */
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/ieee80211_ioctl.h#1 $
|
||||
*/
|
||||
|
||||
#ifndef _IEEE80211_IOCTL_H_
|
||||
#define _IEEE80211_IOCTL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Extracted from the MADWIFI net80211/ieee80211_ioctl.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* WPA/RSN get/set key request. Specify the key/cipher
|
||||
* type and whether the key is to be used for sending and/or
|
||||
* receiving. The key index should be set only when working
|
||||
* with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
|
||||
* Otherwise a unicast/pairwise key is specified by the bssid
|
||||
* (on a station) or mac address (on an ap). They key length
|
||||
* must include any MIC key data; otherwise it should be no
|
||||
more than IEEE80211_KEYBUF_SIZE.
|
||||
*/
|
||||
struct ieee80211req_key {
|
||||
u_int8_t ik_type; /* key/cipher type */
|
||||
u_int8_t ik_pad;
|
||||
u_int16_t ik_keyix; /* key index */
|
||||
u_int8_t ik_keylen; /* key length in bytes */
|
||||
u_int8_t ik_flags;
|
||||
#define IEEE80211_KEY_XMIT 0x01
|
||||
#define IEEE80211_KEY_RECV 0x02
|
||||
#define IEEE80211_KEY_DEFAULT 0x80 /* default xmit key */
|
||||
u_int8_t ik_macaddr[IEEE80211_ADDR_LEN];
|
||||
u_int64_t ik_keyrsc; /* key receive sequence counter */
|
||||
u_int64_t ik_keytsc; /* key transmit sequence counter */
|
||||
u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
|
||||
};
|
||||
/*
|
||||
* Delete a key either by index or address. Set the index
|
||||
* to IEEE80211_KEYIX_NONE when deleting a unicast key.
|
||||
*/
|
||||
struct ieee80211req_del_key {
|
||||
u_int8_t idk_keyix; /* key index */
|
||||
u_int8_t idk_macaddr[IEEE80211_ADDR_LEN];
|
||||
};
|
||||
/*
|
||||
* MLME state manipulation request. IEEE80211_MLME_ASSOC
|
||||
* only makes sense when operating as a station. The other
|
||||
* requests can be used when operating as a station or an
|
||||
* ap (to effect a station).
|
||||
*/
|
||||
struct ieee80211req_mlme {
|
||||
u_int8_t im_op; /* operation to perform */
|
||||
#define IEEE80211_MLME_ASSOC 1 /* associate station */
|
||||
#define IEEE80211_MLME_DISASSOC 2 /* disassociate station */
|
||||
#define IEEE80211_MLME_DEAUTH 3 /* deauthenticate station */
|
||||
#define IEEE80211_MLME_AUTHORIZE 4 /* authorize station */
|
||||
#define IEEE80211_MLME_UNAUTHORIZE 5 /* unauthorize station */
|
||||
u_int16_t im_reason; /* 802.11 reason code */
|
||||
u_int8_t im_macaddr[IEEE80211_ADDR_LEN];
|
||||
};
|
||||
|
||||
struct ieee80211req_addpmkid {
|
||||
u_int8_t pi_bssid[IEEE80211_ADDR_LEN];
|
||||
u_int8_t pi_enable;
|
||||
u_int8_t pi_pmkid[16];
|
||||
};
|
||||
|
||||
#define AUTH_ALG_OPEN_SYSTEM 0x01
|
||||
#define AUTH_ALG_SHARED_KEY 0x02
|
||||
#define AUTH_ALG_LEAP 0x04
|
||||
|
||||
struct ieee80211req_authalg {
|
||||
u_int8_t auth_alg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Request to add an IE to a Management Frame
|
||||
*/
|
||||
enum{
|
||||
IEEE80211_APPIE_FRAME_BEACON = 0,
|
||||
IEEE80211_APPIE_FRAME_PROBE_REQ = 1,
|
||||
IEEE80211_APPIE_FRAME_PROBE_RESP = 2,
|
||||
IEEE80211_APPIE_FRAME_ASSOC_REQ = 3,
|
||||
IEEE80211_APPIE_FRAME_ASSOC_RESP = 4,
|
||||
IEEE80211_APPIE_NUM_OF_FRAME = 5
|
||||
};
|
||||
|
||||
/*
|
||||
* The Maximum length of the IE that can be added to a Management frame
|
||||
*/
|
||||
#define IEEE80211_APPIE_FRAME_MAX_LEN 78
|
||||
|
||||
struct ieee80211req_getset_appiebuf {
|
||||
u_int32_t app_frmtype; /* management frame type for which buffer is added */
|
||||
u_int32_t app_buflen; /*application supplied buffer length */
|
||||
u_int8_t app_buf[];
|
||||
};
|
||||
|
||||
/*
|
||||
* The following definitions are used by an application to set filter
|
||||
* for receiving management frames
|
||||
*/
|
||||
enum {
|
||||
IEEE80211_FILTER_TYPE_BEACON = 0x1,
|
||||
IEEE80211_FILTER_TYPE_PROBE_REQ = 0x2,
|
||||
IEEE80211_FILTER_TYPE_PROBE_RESP = 0x4,
|
||||
IEEE80211_FILTER_TYPE_ASSOC_REQ = 0x8,
|
||||
IEEE80211_FILTER_TYPE_ASSOC_RESP = 0x10,
|
||||
IEEE80211_FILTER_TYPE_AUTH = 0x20,
|
||||
IEEE80211_FILTER_TYPE_DEAUTH = 0x40,
|
||||
IEEE80211_FILTER_TYPE_DISASSOC = 0x80,
|
||||
IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */
|
||||
};
|
||||
|
||||
struct ieee80211req_set_filter {
|
||||
u_int32_t app_filterype; /* management frame filter type */
|
||||
};
|
||||
|
||||
enum {
|
||||
IEEE80211_PARAM_AUTHMODE = 3, /* Authentication Mode */
|
||||
IEEE80211_PARAM_MCASTCIPHER = 5,
|
||||
IEEE80211_PARAM_MCASTKEYLEN = 6, /* multicast key length */
|
||||
IEEE80211_PARAM_UCASTCIPHER = 8,
|
||||
IEEE80211_PARAM_UCASTKEYLEN = 9, /* unicast key length */
|
||||
IEEE80211_PARAM_WPA = 10, /* WPA mode (0,1,2) */
|
||||
IEEE80211_PARAM_ROAMING = 12, /* roaming mode */
|
||||
IEEE80211_PARAM_PRIVACY = 13, /* privacy invoked */
|
||||
IEEE80211_PARAM_COUNTERMEASURES = 14, /* WPA/TKIP countermeasures */
|
||||
IEEE80211_PARAM_DROPUNENCRYPTED = 15, /* discard unencrypted frames */
|
||||
};
|
||||
|
||||
/*
|
||||
* Values for IEEE80211_PARAM_WPA
|
||||
*/
|
||||
#define WPA_MODE_WPA1 1
|
||||
#define WPA_MODE_WPA2 2
|
||||
#define WPA_MODE_AUTO 3
|
||||
#define WPA_MODE_NONE 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IEEE80211_IOCTL_H_ */
|
|
@ -0,0 +1,77 @@
|
|||
/*-
|
||||
* Copyright (c) 2001 Atsushi Onoe
|
||||
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
|
||||
* Copyright (c) 2006 Atheros Communications, Inc.
|
||||
*
|
||||
* Wireless Network driver for Atheros AR6001
|
||||
* All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef _IEEE80211_NODE_H_
|
||||
#define _IEEE80211_NODE_H_
|
||||
|
||||
/*
|
||||
* Node locking definitions.
|
||||
*/
|
||||
#define IEEE80211_NODE_LOCK_INIT(_nt) A_MUTEX_INIT(&(_nt)->nt_nodelock)
|
||||
#define IEEE80211_NODE_LOCK_DESTROY(_nt)
|
||||
#define IEEE80211_NODE_LOCK(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
|
||||
#define IEEE80211_NODE_UNLOCK(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
|
||||
#define IEEE80211_NODE_LOCK_BH(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
|
||||
#define IEEE80211_NODE_UNLOCK_BH(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
|
||||
#define IEEE80211_NODE_LOCK_ASSERT(_nt)
|
||||
|
||||
/*
|
||||
* Node reference counting definitions.
|
||||
*
|
||||
* ieee80211_node_initref initialize the reference count to 1
|
||||
* ieee80211_node_incref add a reference
|
||||
* ieee80211_node_decref remove a reference
|
||||
* ieee80211_node_dectestref remove a reference and return 1 if this
|
||||
* is the last reference, otherwise 0
|
||||
* ieee80211_node_refcnt reference count for printing (only)
|
||||
*/
|
||||
#define ieee80211_node_initref(_ni) ((_ni)->ni_refcnt = 1)
|
||||
#define ieee80211_node_incref(_ni) ((_ni)->ni_refcnt++)
|
||||
#define ieee80211_node_decref(_ni) ((_ni)->ni_refcnt--)
|
||||
#define ieee80211_node_dectestref(_ni) (((_ni)->ni_refcnt--) == 0)
|
||||
#define ieee80211_node_refcnt(_ni) ((_ni)->ni_refcnt)
|
||||
|
||||
#define IEEE80211_NODE_HASHSIZE 32
|
||||
/* simple hash is enough for variation of macaddr */
|
||||
#define IEEE80211_NODE_HASH(addr) \
|
||||
(((const A_UINT8 *)(addr))[IEEE80211_ADDR_LEN - 1] % \
|
||||
IEEE80211_NODE_HASHSIZE)
|
||||
|
||||
/*
|
||||
* Table of ieee80211_node instances. Each ieee80211com
|
||||
* has at least one for holding the scan candidates.
|
||||
* When operating as an access point or in ibss mode there
|
||||
* is a second table for associated stations or neighbors.
|
||||
*/
|
||||
struct ieee80211_node_table {
|
||||
void *nt_wmip; /* back reference */
|
||||
A_MUTEX_T nt_nodelock; /* on node table */
|
||||
struct bss *nt_node_first; /* information of all nodes */
|
||||
struct bss *nt_node_last; /* information of all nodes */
|
||||
struct bss *nt_hash[IEEE80211_NODE_HASHSIZE];
|
||||
const char *nt_name; /* for debugging */
|
||||
A_UINT32 nt_scangen; /* gen# for timeout scan */
|
||||
A_TIMER nt_inact_timer;
|
||||
A_UINT8 isTimerArmed; /* is the node timer armed */
|
||||
};
|
||||
|
||||
#define WLAN_NODE_INACT_TIMEOUT_MSEC 10000
|
||||
|
||||
#endif /* _IEEE80211_NODE_H_ */
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
#ifndef _INI_DSET_H_
|
||||
#define _INI_DSET_H_
|
||||
|
||||
/*
|
||||
* Each of these represents a WHAL INI table, which consists
|
||||
* of an "address column" followed by 1 or more "value columns".
|
||||
*
|
||||
* Software uses the base WHAL_INI_DATA_ID+column to access a
|
||||
* DataSet that holds a particular column of data.
|
||||
*/
|
||||
typedef enum {
|
||||
WHAL_INI_DATA_ID_NULL =0,
|
||||
WHAL_INI_DATA_ID_MODE_SPECIFIC =1, /* 2,3 */
|
||||
WHAL_INI_DATA_ID_COMMON =4, /* 5 */
|
||||
WHAL_INI_DATA_ID_BB_RFGAIN =6, /* 7,8 */
|
||||
WHAL_INI_DATA_ID_ANALOG_BANK1 =9, /* 10 */
|
||||
WHAL_INI_DATA_ID_ANALOG_BANK2 =11, /* 12 */
|
||||
WHAL_INI_DATA_ID_ANALOG_BANK3 =13, /* 14, 15 */
|
||||
WHAL_INI_DATA_ID_ANALOG_BANK6 =16, /* 17, 18 */
|
||||
WHAL_INI_DATA_ID_ANALOG_BANK7 =19, /* 20 */
|
||||
WHAL_INI_DATA_ID_MODE_OVERRIDES =21, /* 22,23 */
|
||||
WHAL_INI_DATA_ID_COMMON_OVERRIDES =24, /* 25 */
|
||||
|
||||
WHAL_INI_DATA_ID_MAX =25
|
||||
} WHAL_INI_DATA_ID;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT16 freqIndex; // 1 - A mode 2 - B or G mode 0 - common
|
||||
A_UINT16 offset;
|
||||
A_UINT32 newValue;
|
||||
} POSTPACK INI_DSET_REG_OVERRIDE;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Atheros Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This module contains the header files for regulatory module,
|
||||
* which include the DB schema and DB values.
|
||||
* $Id:
|
||||
*/
|
||||
|
||||
#ifndef __REG_DB_H__
|
||||
#define __REG_DB_H__
|
||||
|
||||
#include "./regulatory/reg_dbschema.h"
|
||||
#include "./regulatory/reg_dbvalues.h"
|
||||
|
||||
#endif /* __REG_DB_H__ */
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef __REGDUMP_H__
|
||||
#define __REGDUMP_H__
|
||||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
#if defined(AR6001)
|
||||
#include "AR6001/AR6001_regdump.h"
|
||||
#endif
|
||||
#if defined(AR6002)
|
||||
#include "AR6002/AR6002_regdump.h"
|
||||
#endif
|
||||
|
||||
#if !defined(__ASSEMBLER__)
|
||||
/*
|
||||
* Target CPU state at the time of failure is reflected
|
||||
* in a register dump, which the Host can fetch through
|
||||
* the diagnostic window.
|
||||
*/
|
||||
struct register_dump_s {
|
||||
A_UINT32 target_id; /* Target ID */
|
||||
A_UINT32 assline; /* Line number (if assertion failure) */
|
||||
A_UINT32 pc; /* Program Counter at time of exception */
|
||||
A_UINT32 badvaddr; /* Virtual address causing exception */
|
||||
CPU_exception_frame_t exc_frame; /* CPU-specific exception info */
|
||||
|
||||
/* Could copy top of stack here, too.... */
|
||||
};
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* __REGDUMP_H__ */
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TARGADDRS_H__
|
||||
#define __TARGADDRS_H__
|
||||
#if defined(AR6001)
|
||||
#include "AR6001/addrs.h"
|
||||
#endif
|
||||
#if defined(AR6002)
|
||||
#include "AR6002/addrs.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AR6K option bits, to enable/disable various features.
|
||||
* By default, all option bits are 0.
|
||||
* These bits can be set in LOCAL_SCRATCH register 0.
|
||||
*/
|
||||
#define AR6K_OPTION_BMI_DISABLE 0x01 /* Disable BMI comm with Host */
|
||||
#define AR6K_OPTION_SERIAL_ENABLE 0x02 /* Enable serial port msgs */
|
||||
#define AR6K_OPTION_WDT_DISABLE 0x04 /* WatchDog Timer override */
|
||||
#define AR6K_OPTION_SLEEP_DISABLE 0x08 /* Disable system sleep */
|
||||
#define AR6K_OPTION_STOP_BOOT 0x10 /* Stop boot processes (for ATE) */
|
||||
#define AR6K_OPTION_ENABLE_NOANI 0x20 /* Operate without ANI */
|
||||
#define AR6K_OPTION_DSET_DISABLE 0x40 /* Ignore DataSets */
|
||||
#define AR6K_OPTION_IGNORE_FLASH 0x80 /* Ignore flash during bootup */
|
||||
|
||||
/*
|
||||
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
|
||||
* host_interest structure. It must match the address of the _host_interest
|
||||
* symbol (see linker script).
|
||||
*
|
||||
* Host Interest is shared between Host and Target in order to coordinate
|
||||
* between the two, and is intended to remain constant (with additions only
|
||||
* at the end) across software releases.
|
||||
*/
|
||||
#define AR6001_HOST_INTEREST_ADDRESS 0x80000600
|
||||
#define AR6002_HOST_INTEREST_ADDRESS 0x00500400
|
||||
|
||||
#define HOST_INTEREST_MAX_SIZE 0x100
|
||||
|
||||
#if !defined(__ASSEMBLER__)
|
||||
struct register_dump_s;
|
||||
struct dbglog_hdr_s;
|
||||
|
||||
/*
|
||||
* These are items that the Host may need to access
|
||||
* via BMI or via the Diagnostic Window. The position
|
||||
* of items in this structure must remain constant
|
||||
* across firmware revisions!
|
||||
*
|
||||
* Types for each item must be fixed size across
|
||||
* target and host platforms.
|
||||
*
|
||||
* More items may be added at the end.
|
||||
*/
|
||||
struct host_interest_s {
|
||||
/*
|
||||
* Pointer to application-defined area, if any.
|
||||
* Set by Target application during startup.
|
||||
*/
|
||||
A_UINT32 hi_app_host_interest; /* 0x00 */
|
||||
|
||||
/* Pointer to register dump area, valid after Target crash. */
|
||||
A_UINT32 hi_failure_state; /* 0x04 */
|
||||
|
||||
/* Pointer to debug logging header */
|
||||
A_UINT32 hi_dbglog_hdr; /* 0x08 */
|
||||
|
||||
/* Indicates whether or not flash is present on Target.
|
||||
* NB: flash_is_present indicator is here not just
|
||||
* because it might be of interest to the Host; but
|
||||
* also because it's set early on by Target's startup
|
||||
* asm code and we need it to have a special RAM address
|
||||
* so that it doesn't get reinitialized with the rest
|
||||
* of data.
|
||||
*/
|
||||
A_UINT32 hi_flash_is_present; /* 0x0c */
|
||||
|
||||
/*
|
||||
* General-purpose flag bits, similar to AR6000_OPTION_* flags.
|
||||
* Can be used by application rather than by OS.
|
||||
*/
|
||||
A_UINT32 hi_option_flag; /* 0x10 */
|
||||
|
||||
/*
|
||||
* Boolean that determines whether or not to
|
||||
* display messages on the serial port.
|
||||
*/
|
||||
A_UINT32 hi_serial_enable; /* 0x14 */
|
||||
|
||||
/* Start address of Flash DataSet index, if any */
|
||||
A_UINT32 hi_dset_list_head; /* 0x18 */
|
||||
|
||||
/* Override Target application start address */
|
||||
A_UINT32 hi_app_start; /* 0x1c */
|
||||
|
||||
/* Clock and voltage tuning */
|
||||
A_UINT32 hi_skip_clock_init; /* 0x20 */
|
||||
A_UINT32 hi_core_clock_setting; /* 0x24 */
|
||||
A_UINT32 hi_cpu_clock_setting; /* 0x28 */
|
||||
A_UINT32 hi_system_sleep_setting; /* 0x2c */
|
||||
A_UINT32 hi_xtal_control_setting; /* 0x30 */
|
||||
A_UINT32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
|
||||
A_UINT32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
|
||||
A_UINT32 hi_ref_voltage_trim_setting; /* 0x3c */
|
||||
A_UINT32 hi_clock_info; /* 0x40 */
|
||||
|
||||
/*
|
||||
* Flash configuration overrides, used only
|
||||
* when firmware is not executing from flash.
|
||||
* (When using flash, modify the global variables
|
||||
* with equivalent names.)
|
||||
*/
|
||||
A_UINT32 hi_bank0_addr_value; /* 0x44 */
|
||||
A_UINT32 hi_bank0_read_value; /* 0x48 */
|
||||
A_UINT32 hi_bank0_write_value; /* 0x4c */
|
||||
A_UINT32 hi_bank0_config_value; /* 0x50 */
|
||||
|
||||
/* Pointer to Board Data */
|
||||
A_UINT32 hi_board_data; /* 0x54 */
|
||||
A_UINT32 hi_board_data_initialized; /* 0x58 */
|
||||
|
||||
A_UINT32 hi_dset_RAM_index_table; /* 0x5c */
|
||||
|
||||
A_UINT32 hi_desired_baud_rate; /* 0x60 */
|
||||
A_UINT32 hi_dbglog_config; /* 0x64 */
|
||||
A_UINT32 hi_end_RAM_reserve_sz; /* 0x68 */
|
||||
A_UINT32 hi_mbox_io_block_sz; /* 0x6c */
|
||||
|
||||
A_UINT32 hi_num_bpatch_streams; /* 0x70 */
|
||||
A_UINT32 hi_mbox_isr_yield_limit; /* 0x74 */
|
||||
|
||||
A_UINT32 hi_refclk_hz; /* 0x78 */
|
||||
};
|
||||
|
||||
/* Bits defined in hi_option_flag */
|
||||
#define HI_OPTION_TIMER_WAR 1 /* not really used */
|
||||
|
||||
/*
|
||||
* Intended for use by Host software, this macro returns the Target RAM
|
||||
* address of any item in the host_interest structure.
|
||||
* Example: target_addr = AR6001_HOST_INTEREST_ITEM_ADDRESS(hi_board_data);
|
||||
*/
|
||||
#define AR6001_HOST_INTEREST_ITEM_ADDRESS(item) \
|
||||
((A_UINT32)&((((struct host_interest_s *)(AR6001_HOST_INTEREST_ADDRESS))->item)))
|
||||
|
||||
#define AR6002_HOST_INTEREST_ITEM_ADDRESS(item) \
|
||||
((A_UINT32)&((((struct host_interest_s *)(AR6002_HOST_INTEREST_ADDRESS))->item)))
|
||||
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* __TARGADDRS_H__ */
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TESTCMD_H_
|
||||
#define TESTCMD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ZEROES_PATTERN = 0,
|
||||
ONES_PATTERN,
|
||||
REPEATING_10,
|
||||
PN7_PATTERN,
|
||||
PN9_PATTERN,
|
||||
PN15_PATTERN
|
||||
}TX_DATA_PATTERN;
|
||||
|
||||
/* Continous tx
|
||||
mode : TCMD_CONT_TX_OFF - Disabling continous tx
|
||||
TCMD_CONT_TX_SINE - Enable continuous unmodulated tx
|
||||
TCMD_CONT_TX_FRAME- Enable continuous modulated tx
|
||||
freq : Channel freq in Mhz. (e.g 2412 for channel 1 in 11 g)
|
||||
dataRate: 0 - 1 Mbps
|
||||
1 - 2 Mbps
|
||||
2 - 5.5 Mbps
|
||||
3 - 11 Mbps
|
||||
4 - 6 Mbps
|
||||
5 - 9 Mbps
|
||||
6 - 12 Mbps
|
||||
7 - 18 Mbps
|
||||
8 - 24 Mbps
|
||||
9 - 36 Mbps
|
||||
10 - 28 Mbps
|
||||
11 - 54 Mbps
|
||||
txPwr: Tx power in dBm[5 -11] for unmod Tx, [5-14] for mod Tx
|
||||
antenna: 1 - one antenna
|
||||
2 - two antenna
|
||||
Note : Enable/disable continuous tx test cmd works only when target is awake.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TCMD_CONT_TX_OFF = 0,
|
||||
TCMD_CONT_TX_SINE,
|
||||
TCMD_CONT_TX_FRAME,
|
||||
TCMD_CONT_TX_TX99,
|
||||
TCMD_CONT_TX_TX100
|
||||
} TCMD_CONT_TX_MODE;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 testCmdId;
|
||||
A_UINT32 mode;
|
||||
A_UINT32 freq;
|
||||
A_UINT32 dataRate;
|
||||
A_INT32 txPwr;
|
||||
A_UINT32 antenna;
|
||||
A_UINT32 enANI;
|
||||
A_UINT32 scramblerOff;
|
||||
A_UINT32 aifsn;
|
||||
A_UINT16 pktSz;
|
||||
A_UINT16 txPattern;
|
||||
} POSTPACK TCMD_CONT_TX;
|
||||
|
||||
#define TCMD_TXPATTERN_ZERONE 0x1
|
||||
#define TCMD_TXPATTERN_ZERONE_DIS_SCRAMBLE 0x2
|
||||
|
||||
/* Continuous Rx
|
||||
act: TCMD_CONT_RX_PROMIS - promiscuous mode (accept all incoming frames)
|
||||
TCMD_CONT_RX_FILTER - filter mode (accept only frames with dest
|
||||
address equal specified
|
||||
mac address (set via act =3)
|
||||
TCMD_CONT_RX_REPORT off mode (disable cont rx mode and get the
|
||||
report from the last cont
|
||||
Rx test)
|
||||
|
||||
TCMD_CONT_RX_SETMAC - set MacAddr mode (sets the MAC address for the
|
||||
target. This Overrides
|
||||
the default MAC address.)
|
||||
|
||||
*/
|
||||
typedef enum {
|
||||
TCMD_CONT_RX_PROMIS =0,
|
||||
TCMD_CONT_RX_FILTER,
|
||||
TCMD_CONT_RX_REPORT,
|
||||
TCMD_CONT_RX_SETMAC
|
||||
} TCMD_CONT_RX_ACT;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 testCmdId;
|
||||
A_UINT32 act;
|
||||
A_UINT32 enANI;
|
||||
PREPACK union {
|
||||
struct PREPACK TCMD_CONT_RX_PARA {
|
||||
A_UINT32 freq;
|
||||
A_UINT32 antenna;
|
||||
} POSTPACK para;
|
||||
struct PREPACK TCMD_CONT_RX_REPORT {
|
||||
A_UINT32 totalPkt;
|
||||
A_INT32 rssiInDBm;
|
||||
} POSTPACK report;
|
||||
struct PREPACK TCMD_CONT_RX_MAC {
|
||||
A_UCHAR addr[ATH_MAC_LEN];
|
||||
} POSTPACK mac;
|
||||
} POSTPACK u;
|
||||
} POSTPACK TCMD_CONT_RX;
|
||||
|
||||
/* Force sleep/wake test cmd
|
||||
mode: TCMD_PM_WAKEUP - Wakeup the target
|
||||
TCMD_PM_SLEEP - Force the target to sleep.
|
||||
*/
|
||||
typedef enum {
|
||||
TCMD_PM_WAKEUP = 1, /* be consistent with target */
|
||||
TCMD_PM_SLEEP
|
||||
} TCMD_PM_MODE;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 testCmdId;
|
||||
A_UINT32 mode;
|
||||
} POSTPACK TCMD_PM;
|
||||
|
||||
typedef enum{
|
||||
TCMD_CONT_TX_ID,
|
||||
TCMD_CONT_RX_ID,
|
||||
TCMD_PM_ID
|
||||
} TCMD_ID;
|
||||
|
||||
typedef PREPACK union {
|
||||
TCMD_CONT_TX contTx;
|
||||
TCMD_CONT_RX contRx;
|
||||
TCMD_PM pm ;
|
||||
} POSTPACK TEST_CMD;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TESTCMD_H_ */
|
|
@ -0,0 +1,101 @@
|
|||
#ifndef _HOST_WLAN_API_H_
|
||||
#define _HOST_WLAN_API_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file contains the API for the host wlan module
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/wlan_api.h#1 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ieee80211_node_table;
|
||||
struct ieee80211_frame;
|
||||
|
||||
struct ieee80211_common_ie {
|
||||
A_UINT16 ie_chan;
|
||||
A_UINT8 *ie_tstamp;
|
||||
A_UINT8 *ie_ssid;
|
||||
A_UINT8 *ie_rates;
|
||||
A_UINT8 *ie_xrates;
|
||||
A_UINT8 *ie_country;
|
||||
A_UINT8 *ie_wpa;
|
||||
A_UINT8 *ie_rsn;
|
||||
A_UINT8 *ie_wmm;
|
||||
A_UINT8 *ie_ath;
|
||||
A_UINT16 ie_capInfo;
|
||||
A_UINT16 ie_beaconInt;
|
||||
A_UINT8 *ie_tim;
|
||||
A_UINT8 *ie_chswitch;
|
||||
A_UINT8 ie_erp;
|
||||
A_UINT8 *ie_wsc;
|
||||
};
|
||||
|
||||
typedef struct bss {
|
||||
A_UINT8 ni_macaddr[6];
|
||||
A_UINT8 ni_snr;
|
||||
A_INT16 ni_rssi;
|
||||
struct bss *ni_list_next;
|
||||
struct bss *ni_list_prev;
|
||||
struct bss *ni_hash_next;
|
||||
struct bss *ni_hash_prev;
|
||||
struct ieee80211_common_ie ni_cie;
|
||||
A_UINT8 *ni_buf;
|
||||
struct ieee80211_node_table *ni_table;
|
||||
A_UINT32 ni_refcnt;
|
||||
int ni_scangen;
|
||||
A_UINT32 ni_tstamp;
|
||||
} bss_t;
|
||||
|
||||
typedef void wlan_node_iter_func(void *arg, bss_t *);
|
||||
|
||||
bss_t *wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size);
|
||||
void wlan_node_free(bss_t *ni);
|
||||
void wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
|
||||
const A_UINT8 *macaddr);
|
||||
bss_t *wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr);
|
||||
void wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni);
|
||||
void wlan_free_allnodes(struct ieee80211_node_table *nt);
|
||||
void wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
|
||||
void *arg);
|
||||
|
||||
void wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt);
|
||||
void wlan_node_table_reset(struct ieee80211_node_table *nt);
|
||||
void wlan_node_table_cleanup(struct ieee80211_node_table *nt);
|
||||
|
||||
A_STATUS wlan_parse_beacon(A_UINT8 *buf, int framelen,
|
||||
struct ieee80211_common_ie *cie);
|
||||
|
||||
A_UINT16 wlan_ieee2freq(int chan);
|
||||
A_UINT32 wlan_freq2ieee(A_UINT16 freq);
|
||||
|
||||
|
||||
bss_t *
|
||||
wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
|
||||
A_UINT32 ssidLength, A_BOOL bIsWPA2);
|
||||
|
||||
void
|
||||
wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HOST_WLAN_API_H_ */
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Atheros Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WLAN_DSET_H__
|
||||
#define __WKAN_DSET_H__
|
||||
|
||||
typedef PREPACK struct wow_config_dset {
|
||||
|
||||
A_UINT8 valid_dset;
|
||||
A_UINT8 gpio_enable;
|
||||
A_UINT16 gpio_pin;
|
||||
} POSTPACK WOW_CONFIG_DSET;
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,260 @@
|
|||
#ifndef _WMI_API_H_
|
||||
#define _WMI_API_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file contains the definitions for the Wireless Module Interface (WMI).
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/wmi_api.h#2 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IP QoS Field definitions according to 802.1p
|
||||
*/
|
||||
#define BEST_EFFORT_PRI 0
|
||||
#define BACKGROUND_PRI 1
|
||||
#define EXCELLENT_EFFORT_PRI 3
|
||||
#define CONTROLLED_LOAD_PRI 4
|
||||
#define VIDEO_PRI 5
|
||||
#define VOICE_PRI 6
|
||||
#define NETWORK_CONTROL_PRI 7
|
||||
#define MAX_NUM_PRI 8
|
||||
|
||||
#define UNDEFINED_PRI (0xff)
|
||||
|
||||
/* simple mapping of IP TOS field to a WMI priority stream
|
||||
* this mapping was taken from the original linux driver implementation
|
||||
* The operation maps the following
|
||||
*
|
||||
* */
|
||||
#define IP_TOS_TO_WMI_PRI(tos) \
|
||||
((WMI_PRI_STREAM_ID)(((tos) >> 1) & 0x03))
|
||||
|
||||
#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 /* 5 seconds */
|
||||
|
||||
|
||||
struct wmi_t;
|
||||
|
||||
void *wmi_init(void *devt);
|
||||
|
||||
void wmi_qos_state_init(struct wmi_t *wmip);
|
||||
void wmi_shutdown(struct wmi_t *wmip);
|
||||
A_UINT16 wmi_get_mapped_qos_queue(struct wmi_t *, A_UINT8);
|
||||
A_STATUS wmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf);
|
||||
A_STATUS wmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, A_UINT8 msgType);
|
||||
A_STATUS wmi_dot3_2_dix(struct wmi_t *wmip, void *osbuf);
|
||||
A_STATUS wmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf);
|
||||
A_STATUS wmi_syncpoint(struct wmi_t *wmip);
|
||||
A_STATUS wmi_syncpoint_reset(struct wmi_t *wmip);
|
||||
WMI_PRI_STREAM_ID wmi_get_stream_id(struct wmi_t *wmip, A_UINT8 trafficClass);
|
||||
A_UINT8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, A_UINT8 dir, A_UINT8 up);
|
||||
|
||||
A_STATUS wmi_control_rx(struct wmi_t *wmip, void *osbuf);
|
||||
void wmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg);
|
||||
void wmi_free_allnodes(struct wmi_t *wmip);
|
||||
bss_t *wmi_find_node(struct wmi_t *wmip, const A_UINT8 *macaddr);
|
||||
|
||||
|
||||
typedef enum {
|
||||
NO_SYNC_WMIFLAG = 0,
|
||||
SYNC_BEFORE_WMIFLAG, /* transmit all queued data before cmd */
|
||||
SYNC_AFTER_WMIFLAG, /* any new data waits until cmd execs */
|
||||
SYNC_BOTH_WMIFLAG,
|
||||
END_WMIFLAG /* end marker */
|
||||
} WMI_SYNC_FLAG;
|
||||
|
||||
A_STATUS wmi_cmd_send(struct wmi_t *wmip, void *osbuf, WMI_COMMAND_ID cmdId,
|
||||
WMI_SYNC_FLAG flag);
|
||||
A_STATUS wmi_connect_cmd(struct wmi_t *wmip,
|
||||
NETWORK_TYPE netType,
|
||||
DOT11_AUTH_MODE dot11AuthMode,
|
||||
AUTH_MODE authMode,
|
||||
CRYPTO_TYPE pairwiseCrypto,
|
||||
A_UINT8 pairwiseCryptoLen,
|
||||
CRYPTO_TYPE groupCrypto,
|
||||
A_UINT8 groupCryptoLen,
|
||||
int ssidLength,
|
||||
A_UCHAR *ssid,
|
||||
A_UINT8 *bssid,
|
||||
A_UINT16 channel,
|
||||
A_UINT32 ctrl_flags);
|
||||
A_STATUS wmi_reconnect_cmd(struct wmi_t *wmip,
|
||||
A_UINT8 *bssid,
|
||||
A_UINT16 channel);
|
||||
A_STATUS wmi_disconnect_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_getrev_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_startscan_cmd(struct wmi_t *wmip, WMI_SCAN_TYPE scanType,
|
||||
A_BOOL forceFgScan, A_BOOL isLegacy,
|
||||
A_UINT32 homeDwellTime, A_UINT32 forceScanInterval);
|
||||
A_STATUS wmi_scanparams_cmd(struct wmi_t *wmip, A_UINT16 fg_start_sec,
|
||||
A_UINT16 fg_end_sec, A_UINT16 bg_sec,
|
||||
A_UINT16 minact_chdw_msec,
|
||||
A_UINT16 maxact_chdw_msec, A_UINT16 pas_chdw_msec,
|
||||
A_UINT8 shScanRatio, A_UINT8 scanCtrlFlags,
|
||||
A_UINT32 max_dfsch_act_time);
|
||||
A_STATUS wmi_bssfilter_cmd(struct wmi_t *wmip, A_UINT8 filter, A_UINT32 ieMask);
|
||||
A_STATUS wmi_probedSsid_cmd(struct wmi_t *wmip, A_UINT8 index, A_UINT8 flag,
|
||||
A_UINT8 ssidLength, A_UCHAR *ssid);
|
||||
A_STATUS wmi_listeninterval_cmd(struct wmi_t *wmip, A_UINT16 listenInterval, A_UINT16 listenBeacons);
|
||||
A_STATUS wmi_bmisstime_cmd(struct wmi_t *wmip, A_UINT16 bmisstime, A_UINT16 bmissbeacons);
|
||||
A_STATUS wmi_associnfo_cmd(struct wmi_t *wmip, A_UINT8 ieType,
|
||||
A_UINT8 ieLen, A_UINT8 *ieInfo);
|
||||
A_STATUS wmi_powermode_cmd(struct wmi_t *wmip, A_UINT8 powerMode);
|
||||
A_STATUS wmi_ibsspmcaps_cmd(struct wmi_t *wmip, A_UINT8 pmEnable, A_UINT8 ttl,
|
||||
A_UINT16 atim_windows, A_UINT16 timeout_value);
|
||||
A_STATUS wmi_pmparams_cmd(struct wmi_t *wmip, A_UINT16 idlePeriod,
|
||||
A_UINT16 psPollNum, A_UINT16 dtimPolicy);
|
||||
A_STATUS wmi_disctimeout_cmd(struct wmi_t *wmip, A_UINT8 timeout);
|
||||
A_STATUS wmi_sync_cmd(struct wmi_t *wmip, A_UINT8 syncNumber);
|
||||
A_STATUS wmi_create_pstream_cmd(struct wmi_t *wmip, WMI_CREATE_PSTREAM_CMD *pstream);
|
||||
A_STATUS wmi_delete_pstream_cmd(struct wmi_t *wmip, A_UINT8 trafficClass, A_UINT8 streamID);
|
||||
A_STATUS wmi_set_bitrate_cmd(struct wmi_t *wmip, A_INT32 rate);
|
||||
A_STATUS wmi_get_bitrate_cmd(struct wmi_t *wmip);
|
||||
A_INT8 wmi_validate_bitrate(struct wmi_t *wmip, A_INT32 rate);
|
||||
A_STATUS wmi_get_regDomain_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_get_channelList_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_set_channelParams_cmd(struct wmi_t *wmip, A_UINT8 scanParam,
|
||||
WMI_PHY_MODE mode, A_INT8 numChan,
|
||||
A_UINT16 *channelList);
|
||||
|
||||
A_STATUS wmi_set_snr_threshold_params(struct wmi_t *wmip,
|
||||
WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
|
||||
A_STATUS wmi_set_rssi_threshold_params(struct wmi_t *wmip,
|
||||
WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
|
||||
A_STATUS wmi_clr_rssi_snr(struct wmi_t *wmip);
|
||||
A_STATUS wmi_set_lq_threshold_params(struct wmi_t *wmip,
|
||||
WMI_LQ_THRESHOLD_PARAMS_CMD *lqCmd);
|
||||
A_STATUS wmi_set_rts_cmd(struct wmi_t *wmip, A_UINT16 threshold);
|
||||
A_STATUS wmi_set_lpreamble_cmd(struct wmi_t *wmip, A_UINT8 status);
|
||||
|
||||
A_STATUS wmi_set_error_report_bitmask(struct wmi_t *wmip, A_UINT32 bitmask);
|
||||
|
||||
A_STATUS wmi_get_challenge_resp_cmd(struct wmi_t *wmip, A_UINT32 cookie,
|
||||
A_UINT32 source);
|
||||
A_STATUS wmi_config_debug_module_cmd(struct wmi_t *wmip, A_UINT16 mmask,
|
||||
A_UINT16 tsr, A_BOOL rep, A_UINT16 size,
|
||||
A_UINT32 valid);
|
||||
A_STATUS wmi_get_stats_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_addKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex,
|
||||
CRYPTO_TYPE keyType, A_UINT8 keyUsage,
|
||||
A_UINT8 keyLength,A_UINT8 *keyRSC,
|
||||
A_UINT8 *keyMaterial, A_UINT8 key_op_ctrl,
|
||||
WMI_SYNC_FLAG sync_flag);
|
||||
A_STATUS wmi_add_krk_cmd(struct wmi_t *wmip, A_UINT8 *krk);
|
||||
A_STATUS wmi_delete_krk_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_deleteKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex);
|
||||
A_STATUS wmi_set_akmp_params_cmd(struct wmi_t *wmip,
|
||||
WMI_SET_AKMP_PARAMS_CMD *akmpParams);
|
||||
A_STATUS wmi_get_pmkid_list_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_set_pmkid_list_cmd(struct wmi_t *wmip,
|
||||
WMI_SET_PMKID_LIST_CMD *pmkInfo);
|
||||
A_STATUS wmi_set_txPwr_cmd(struct wmi_t *wmip, A_UINT8 dbM);
|
||||
A_STATUS wmi_get_txPwr_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_switch_radio(struct wmi_t *wmip, A_UINT8 on);
|
||||
A_STATUS wmi_addBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex, A_UINT8 *bssid);
|
||||
A_STATUS wmi_deleteBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex);
|
||||
A_STATUS wmi_set_tkip_countermeasures_cmd(struct wmi_t *wmip, A_BOOL en);
|
||||
A_STATUS wmi_setPmkid_cmd(struct wmi_t *wmip, A_UINT8 *bssid, A_UINT8 *pmkId,
|
||||
A_BOOL set);
|
||||
A_STATUS wmi_set_access_params_cmd(struct wmi_t *wmip, A_UINT16 txop,
|
||||
A_UINT8 eCWmin, A_UINT8 eCWmax,
|
||||
A_UINT8 aifsn);
|
||||
A_STATUS wmi_set_retry_limits_cmd(struct wmi_t *wmip, A_UINT8 frameType,
|
||||
A_UINT8 trafficClass, A_UINT8 maxRetries,
|
||||
A_UINT8 enableNotify);
|
||||
|
||||
void wmi_get_current_bssid(struct wmi_t *wmip, A_UINT8 *bssid);
|
||||
|
||||
A_STATUS wmi_get_roam_tbl_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_get_roam_data_cmd(struct wmi_t *wmip, A_UINT8 roamDataType);
|
||||
A_STATUS wmi_set_roam_ctrl_cmd(struct wmi_t *wmip, WMI_SET_ROAM_CTRL_CMD *p,
|
||||
A_UINT8 size);
|
||||
A_STATUS wmi_set_powersave_timers_cmd(struct wmi_t *wmip,
|
||||
WMI_POWERSAVE_TIMERS_POLICY_CMD *pCmd,
|
||||
A_UINT8 size);
|
||||
|
||||
A_STATUS wmi_set_opt_mode_cmd(struct wmi_t *wmip, A_UINT8 optMode);
|
||||
A_STATUS wmi_opt_tx_frame_cmd(struct wmi_t *wmip,
|
||||
A_UINT8 frmType,
|
||||
A_UINT8 *dstMacAddr,
|
||||
A_UINT8 *bssid,
|
||||
A_UINT16 optIEDataLen,
|
||||
A_UINT8 *optIEData);
|
||||
|
||||
A_STATUS wmi_set_adhoc_bconIntvl_cmd(struct wmi_t *wmip, A_UINT16 intvl);
|
||||
A_STATUS wmi_set_voice_pkt_size_cmd(struct wmi_t *wmip, A_UINT16 voicePktSize);
|
||||
A_STATUS wmi_set_max_sp_len_cmd(struct wmi_t *wmip, A_UINT8 maxSpLen);
|
||||
A_UINT8 convert_userPriority_to_trafficClass(A_UINT8 userPriority);
|
||||
A_UINT8 wmi_get_power_mode_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_verify_tspec_params(WMI_CREATE_PSTREAM_CMD *pCmd, A_BOOL tspecCompliance);
|
||||
|
||||
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
||||
A_STATUS wmi_test_cmd(struct wmi_t *wmip, A_UINT8 *buf, A_UINT32 len);
|
||||
#endif
|
||||
|
||||
A_STATUS wmi_set_bt_status_cmd(struct wmi_t *wmip, A_UINT8 streamType, A_UINT8 status);
|
||||
A_STATUS wmi_set_bt_params_cmd(struct wmi_t *wmip, WMI_SET_BT_PARAMS_CMD* cmd);
|
||||
|
||||
|
||||
/*
|
||||
* This function is used to configure the fix rates mask to the target.
|
||||
*/
|
||||
A_STATUS wmi_set_fixrates_cmd(struct wmi_t *wmip, A_INT16 fixRatesMask);
|
||||
A_STATUS wmi_get_ratemask_cmd(struct wmi_t *wmip);
|
||||
|
||||
A_STATUS wmi_set_authmode_cmd(struct wmi_t *wmip, A_UINT8 mode);
|
||||
|
||||
A_STATUS wmi_set_reassocmode_cmd(struct wmi_t *wmip, A_UINT8 mode);
|
||||
|
||||
A_STATUS wmi_set_wmm_cmd(struct wmi_t *wmip, WMI_WMM_STATUS status);
|
||||
A_STATUS wmi_set_wmm_txop(struct wmi_t *wmip, WMI_TXOP_CFG txEnable);
|
||||
|
||||
A_STATUS wmi_get_keepalive_configured(struct wmi_t *wmip);
|
||||
A_UINT8 wmi_get_keepalive_cmd(struct wmi_t *wmip);
|
||||
A_STATUS wmi_set_keepalive_cmd(struct wmi_t *wmip, A_UINT8 keepaliveInterval);
|
||||
|
||||
A_STATUS wmi_set_appie_cmd(struct wmi_t *wmip, A_UINT8 mgmtFrmType,
|
||||
A_UINT8 ieLen,A_UINT8 *ieInfo);
|
||||
|
||||
A_STATUS wmi_set_halparam_cmd(struct wmi_t *wmip, A_UINT8 *cmd, A_UINT16 dataLen);
|
||||
A_INT32 wmi_get_rate(A_INT8 rateindex);
|
||||
|
||||
/*Wake on Wireless WMI commands*/
|
||||
A_STATUS wmi_set_host_sleep_mode_cmd(struct wmi_t *wmip, WMI_SET_HOST_SLEEP_MODE_CMD *cmd);
|
||||
A_STATUS wmi_set_wow_mode_cmd(struct wmi_t *wmip, WMI_SET_WOW_MODE_CMD *cmd);
|
||||
A_STATUS wmi_get_wow_list_cmd(struct wmi_t *wmip, WMI_GET_WOW_LIST_CMD *cmd);
|
||||
A_STATUS wmi_add_wow_pattern_cmd(struct wmi_t *wmip,
|
||||
WMI_ADD_WOW_PATTERN_CMD *cmd, A_UINT8* pattern, A_UINT8* mask, A_UINT8 pattern_size);
|
||||
A_STATUS wmi_del_wow_pattern_cmd(struct wmi_t *wmip,
|
||||
WMI_DEL_WOW_PATTERN_CMD *cmd);
|
||||
A_STATUS wmi_set_wsc_status_cmd(struct wmi_t *wmip, A_UINT32 status);
|
||||
|
||||
bss_t *
|
||||
wmi_find_Ssidnode (struct wmi_t *wmip, A_UCHAR *pSsid,
|
||||
A_UINT32 ssidLength, A_BOOL bIsWPA2);
|
||||
|
||||
void
|
||||
wmi_node_return (struct wmi_t *wmip, bss_t *bss);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _WMI_API_H_ */
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* $ATH_LICENSE_HOSTSDK0_C$
|
||||
*
|
||||
* This file contains extensions of the WMI protocol specified in the
|
||||
* Wireless Module Interface (WMI). It includes definitions of all
|
||||
* extended commands and events. Extensions include useful commands
|
||||
* that are not directly related to wireless activities. They may
|
||||
* be hardware-specific, and they might not be supported on all
|
||||
* implementations.
|
||||
*
|
||||
* Extended WMIX commands are encapsulated in a WMI message with
|
||||
* cmd=WMI_EXTENSION_CMD.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _WMIX_H_
|
||||
#define _WMIX_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ATH_TARGET
|
||||
#include "athstartpack.h"
|
||||
#endif
|
||||
|
||||
#include "dbglog.h"
|
||||
|
||||
/*
|
||||
* Extended WMI commands are those that are needed during wireless
|
||||
* operation, but which are not really wireless commands. This allows,
|
||||
* for instance, platform-specific commands. Extended WMI commands are
|
||||
* embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID.
|
||||
* Extended WMI events are similarly embedded in a WMI event message with
|
||||
* WMI_EVENT_ID=WMI_EXTENSION_EVENTID.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 commandId;
|
||||
} POSTPACK WMIX_CMD_HDR;
|
||||
|
||||
typedef enum {
|
||||
WMIX_DSETOPEN_REPLY_CMDID = 0x2001,
|
||||
WMIX_DSETDATA_REPLY_CMDID,
|
||||
WMIX_GPIO_OUTPUT_SET_CMDID,
|
||||
WMIX_GPIO_INPUT_GET_CMDID,
|
||||
WMIX_GPIO_REGISTER_SET_CMDID,
|
||||
WMIX_GPIO_REGISTER_GET_CMDID,
|
||||
WMIX_GPIO_INTR_ACK_CMDID,
|
||||
WMIX_HB_CHALLENGE_RESP_CMDID,
|
||||
WMIX_DBGLOG_CFG_MODULE_CMDID,
|
||||
} WMIX_COMMAND_ID;
|
||||
|
||||
typedef enum {
|
||||
WMIX_DSETOPENREQ_EVENTID = 0x3001,
|
||||
WMIX_DSETCLOSE_EVENTID,
|
||||
WMIX_DSETDATAREQ_EVENTID,
|
||||
WMIX_GPIO_INTR_EVENTID,
|
||||
WMIX_GPIO_DATA_EVENTID,
|
||||
WMIX_GPIO_ACK_EVENTID,
|
||||
WMIX_HB_CHALLENGE_RESP_EVENTID,
|
||||
WMIX_DBGLOG_EVENTID,
|
||||
} WMIX_EVENT_ID;
|
||||
|
||||
/*
|
||||
* =============DataSet support=================
|
||||
*/
|
||||
|
||||
/*
|
||||
* WMIX_DSETOPENREQ_EVENTID
|
||||
* DataSet Open Request Event
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 dset_id;
|
||||
A_UINT32 targ_dset_handle; /* echo'ed, not used by Host, */
|
||||
A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */
|
||||
A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */
|
||||
} POSTPACK WMIX_DSETOPENREQ_EVENT;
|
||||
|
||||
/*
|
||||
* WMIX_DSETCLOSE_EVENTID
|
||||
* DataSet Close Event
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 access_cookie;
|
||||
} POSTPACK WMIX_DSETCLOSE_EVENT;
|
||||
|
||||
/*
|
||||
* WMIX_DSETDATAREQ_EVENTID
|
||||
* DataSet Data Request Event
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 access_cookie;
|
||||
A_UINT32 offset;
|
||||
A_UINT32 length;
|
||||
A_UINT32 targ_buf; /* echo'ed, not used by Host, */
|
||||
A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */
|
||||
A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */
|
||||
} POSTPACK WMIX_DSETDATAREQ_EVENT;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 status;
|
||||
A_UINT32 targ_dset_handle;
|
||||
A_UINT32 targ_reply_fn;
|
||||
A_UINT32 targ_reply_arg;
|
||||
A_UINT32 access_cookie;
|
||||
A_UINT32 size;
|
||||
A_UINT32 version;
|
||||
} POSTPACK WMIX_DSETOPEN_REPLY_CMD;
|
||||
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 status;
|
||||
A_UINT32 targ_buf;
|
||||
A_UINT32 targ_reply_fn;
|
||||
A_UINT32 targ_reply_arg;
|
||||
A_UINT32 length;
|
||||
A_UINT8 buf[1];
|
||||
} POSTPACK WMIX_DSETDATA_REPLY_CMD;
|
||||
|
||||
|
||||
/*
|
||||
* =============GPIO support=================
|
||||
* All masks are 18-bit masks with bit N operating on GPIO pin N.
|
||||
*/
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
/*
|
||||
* Set GPIO pin output state.
|
||||
* In order for output to be driven, a pin must be enabled for output.
|
||||
* This can be done during initialization through the GPIO Configuration
|
||||
* DataSet, or during operation with the enable_mask.
|
||||
*
|
||||
* If a request is made to simultaneously set/clear or set/disable or
|
||||
* clear/disable or disable/enable, results are undefined.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 set_mask; /* pins to set */
|
||||
A_UINT32 clear_mask; /* pins to clear */
|
||||
A_UINT32 enable_mask; /* pins to enable for output */
|
||||
A_UINT32 disable_mask; /* pins to disable/tristate */
|
||||
} POSTPACK WMIX_GPIO_OUTPUT_SET_CMD;
|
||||
|
||||
/*
|
||||
* Set a GPIO register. For debug/exceptional cases.
|
||||
* Values for gpioreg_id are GPIO_REGISTER_IDs, defined in a
|
||||
* platform-dependent header.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 gpioreg_id; /* GPIO register ID */
|
||||
A_UINT32 value; /* value to write */
|
||||
} POSTPACK WMIX_GPIO_REGISTER_SET_CMD;
|
||||
|
||||
/* Get a GPIO register. For debug/exceptional cases. */
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 gpioreg_id; /* GPIO register to read */
|
||||
} POSTPACK WMIX_GPIO_REGISTER_GET_CMD;
|
||||
|
||||
/*
|
||||
* Host acknowledges and re-arms GPIO interrupts. A single
|
||||
* message should be used to acknowledge all interrupts that
|
||||
* were delivered in an earlier WMIX_GPIO_INTR_EVENT message.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 ack_mask; /* interrupts to acknowledge */
|
||||
} POSTPACK WMIX_GPIO_INTR_ACK_CMD;
|
||||
|
||||
/*
|
||||
* Target informs Host of GPIO interrupts that have ocurred since the
|
||||
* last WMIX_GIPO_INTR_ACK_CMD was received. Additional information --
|
||||
* the current GPIO input values is provided -- in order to support
|
||||
* use of a GPIO interrupt as a Data Valid signal for other GPIO pins.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 intr_mask; /* pending GPIO interrupts */
|
||||
A_UINT32 input_values; /* recent GPIO input values */
|
||||
} POSTPACK WMIX_GPIO_INTR_EVENT;
|
||||
|
||||
/*
|
||||
* Target responds to Host's earlier WMIX_GPIO_INPUT_GET_CMDID request
|
||||
* using a GPIO_DATA_EVENT with
|
||||
* value set to the mask of GPIO pin inputs and
|
||||
* reg_id set to GPIO_ID_NONE
|
||||
*
|
||||
*
|
||||
* Target responds to Hosts's earlier WMIX_GPIO_REGISTER_GET_CMDID request
|
||||
* using a GPIO_DATA_EVENT with
|
||||
* value set to the value of the requested register and
|
||||
* reg_id identifying the register (reflects the original request)
|
||||
* NB: reg_id supports the future possibility of unsolicited
|
||||
* WMIX_GPIO_DATA_EVENTs (for polling GPIO input), and it may
|
||||
* simplify Host GPIO support.
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 value;
|
||||
A_UINT32 reg_id;
|
||||
} POSTPACK WMIX_GPIO_DATA_EVENT;
|
||||
|
||||
/*
|
||||
* =============Error Detection support=================
|
||||
*/
|
||||
|
||||
/*
|
||||
* WMIX_HB_CHALLENGE_RESP_CMDID
|
||||
* Heartbeat Challenge Response command
|
||||
*/
|
||||
typedef PREPACK struct {
|
||||
A_UINT32 cookie;
|
||||
A_UINT32 source;
|
||||
} POSTPACK WMIX_HB_CHALLENGE_RESP_CMD;
|
||||
|
||||
/*
|
||||
* WMIX_HB_CHALLENGE_RESP_EVENTID
|
||||
* Heartbeat Challenge Response Event
|
||||
*/
|
||||
#define WMIX_HB_CHALLENGE_RESP_EVENT WMIX_HB_CHALLENGE_RESP_CMD
|
||||
|
||||
typedef PREPACK struct {
|
||||
struct dbglog_config_s config;
|
||||
} POSTPACK WMIX_DBGLOG_CFG_MODULE_CMD;
|
||||
|
||||
#ifndef ATH_TARGET
|
||||
#include "athendpack.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _WMIX_H_ */
|
|
@ -0,0 +1,467 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "AR6Khwreg.h"
|
||||
#include "targaddrs.h"
|
||||
#include "a_osapi.h"
|
||||
#include "hif.h"
|
||||
#include "htc_api.h"
|
||||
#include "bmi.h"
|
||||
#include "bmi_msg.h"
|
||||
#include "common_drv.h"
|
||||
#include "a_debug.h"
|
||||
#include "targaddrs.h"
|
||||
|
||||
#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
|
||||
(((TargetType) == TARGET_TYPE_AR6001) ? \
|
||||
AR6001_HOST_INTEREST_ITEM_ADDRESS(item) : \
|
||||
AR6002_HOST_INTEREST_ITEM_ADDRESS(item))
|
||||
|
||||
|
||||
/* Compile the 4BYTE version of the window register setup routine,
|
||||
* This mitigates host interconnect issues with non-4byte aligned bus requests, some
|
||||
* interconnects use bus adapters that impose strict limitations.
|
||||
* Since diag window access is not intended for performance critical operations, the 4byte mode should
|
||||
* be satisfactory even though it generates 4X the bus activity. */
|
||||
|
||||
#ifdef USE_4BYTE_REGISTER_ACCESS
|
||||
|
||||
/* set the window address register (using 4-byte register access ). */
|
||||
A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
|
||||
{
|
||||
A_STATUS status;
|
||||
A_UINT8 addrValue[4];
|
||||
int i;
|
||||
|
||||
/* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
|
||||
* last to initiate the access cycle */
|
||||
|
||||
for (i = 1; i <= 3; i++) {
|
||||
/* fill the buffer with the address byte value we want to hit 4 times*/
|
||||
addrValue[0] = ((A_UINT8 *)&Address)[i];
|
||||
addrValue[1] = addrValue[0];
|
||||
addrValue[2] = addrValue[0];
|
||||
addrValue[3] = addrValue[0];
|
||||
|
||||
/* hit each byte of the register address with a 4-byte write operation to the same address,
|
||||
* this is a harmless operation */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
RegisterAddr+i,
|
||||
addrValue,
|
||||
4,
|
||||
HIF_WR_SYNC_BYTE_FIX,
|
||||
NULL);
|
||||
if (status != A_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
|
||||
RegisterAddr, Address));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* write the address register again, this time write the whole 4-byte value.
|
||||
* The effect here is that the LSB write causes the cycle to start, the extra
|
||||
* 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
RegisterAddr,
|
||||
(A_UCHAR *)(&Address),
|
||||
4,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
|
||||
RegisterAddr, Address));
|
||||
return status;
|
||||
}
|
||||
|
||||
return A_OK;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* set the window address register */
|
||||
A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
|
||||
{
|
||||
A_STATUS status;
|
||||
|
||||
/* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
|
||||
* last to initiate the access cycle */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
RegisterAddr+1, /* write upper 3 bytes */
|
||||
((A_UCHAR *)(&Address))+1,
|
||||
sizeof(A_UINT32)-1,
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
|
||||
RegisterAddr, Address));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* write the LSB of the register, this initiates the operation */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
RegisterAddr,
|
||||
(A_UCHAR *)(&Address),
|
||||
sizeof(A_UINT8),
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
|
||||
RegisterAddr, Address));
|
||||
return status;
|
||||
}
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read from the AR6000 through its diagnostic window.
|
||||
* No cooperation from the Target is required for this.
|
||||
*/
|
||||
A_STATUS
|
||||
ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
|
||||
{
|
||||
A_STATUS status;
|
||||
|
||||
/* set window register to start read cycle */
|
||||
status = ar6000_SetAddressWindowRegister(hifDevice,
|
||||
WINDOW_READ_ADDR_ADDRESS,
|
||||
*address);
|
||||
|
||||
if (status != A_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* read the data */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
WINDOW_DATA_ADDRESS,
|
||||
(A_UCHAR *)data,
|
||||
sizeof(A_UINT32),
|
||||
HIF_RD_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n"));
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write to the AR6000 through its diagnostic window.
|
||||
* No cooperation from the Target is required for this.
|
||||
*/
|
||||
A_STATUS
|
||||
ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
|
||||
{
|
||||
A_STATUS status;
|
||||
|
||||
/* set write data */
|
||||
status = HIFReadWrite(hifDevice,
|
||||
WINDOW_DATA_ADDRESS,
|
||||
(A_UCHAR *)data,
|
||||
sizeof(A_UINT32),
|
||||
HIF_WR_SYNC_BYTE_INC,
|
||||
NULL);
|
||||
if (status != A_OK) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* set window register, which starts the write cycle */
|
||||
return ar6000_SetAddressWindowRegister(hifDevice,
|
||||
WINDOW_WRITE_ADDR_ADDRESS,
|
||||
*address);
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
|
||||
A_UCHAR *data, A_UINT32 length)
|
||||
{
|
||||
A_UINT32 count;
|
||||
A_STATUS status = A_OK;
|
||||
|
||||
for (count = 0; count < length; count += 4, address += 4) {
|
||||
if ((status = ar6000_ReadRegDiag(hifDevice, &address,
|
||||
(A_UINT32 *)&data[count])) != A_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
|
||||
A_UCHAR *data, A_UINT32 length)
|
||||
{
|
||||
A_UINT32 count;
|
||||
A_STATUS status = A_OK;
|
||||
|
||||
for (count = 0; count < length; count += 4, address += 4) {
|
||||
if ((status = ar6000_WriteRegDiag(hifDevice, &address,
|
||||
(A_UINT32 *)&data[count])) != A_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice)
|
||||
{
|
||||
int i;
|
||||
struct forceROM_s {
|
||||
A_UINT32 addr;
|
||||
A_UINT32 data;
|
||||
};
|
||||
struct forceROM_s *ForceROM;
|
||||
int szForceROM;
|
||||
A_UINT32 instruction;
|
||||
|
||||
static struct forceROM_s ForceROM_REV2[] = {
|
||||
/* NB: This works for old REV2 ROM (old). */
|
||||
{0x00001ff0, 0x175b0027}, /* jump instruction at 0xa0001ff0 */
|
||||
{0x00001ff4, 0x00000000}, /* nop instruction at 0xa0001ff4 */
|
||||
|
||||
{MC_REMAP_TARGET_ADDRESS, 0x00001ff0}, /* remap to 0xa0001ff0 */
|
||||
{MC_REMAP_COMPARE_ADDRESS, 0x01000040},/* ...from 0xbfc00040 */
|
||||
{MC_REMAP_SIZE_ADDRESS, 0x00000000}, /* ...1 cache line */
|
||||
{MC_REMAP_VALID_ADDRESS, 0x00000001}, /* ...remap is valid */
|
||||
|
||||
{LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */
|
||||
|
||||
{RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK},
|
||||
};
|
||||
|
||||
static struct forceROM_s ForceROM_NEW[] = {
|
||||
/* NB: This works for AR6000 ROM REV3 and beyond. */
|
||||
{LOCAL_SCRATCH_ADDRESS, AR6K_OPTION_IGNORE_FLASH},
|
||||
{LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */
|
||||
{RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK},
|
||||
};
|
||||
|
||||
/*
|
||||
* Examine a semi-arbitrary instruction that's different
|
||||
* in REV2 and other revisions.
|
||||
* NB: If a Host port does not require simultaneous support
|
||||
* for multiple revisions of Target ROM, this code can be elided.
|
||||
*/
|
||||
(void)ar6000_ReadDataDiag(hifDevice, 0x01000040,
|
||||
(A_UCHAR *)&instruction, 4);
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("instruction=0x%x\n", instruction));
|
||||
|
||||
if (instruction == 0x3c1aa200) {
|
||||
/* It's an old ROM */
|
||||
ForceROM = ForceROM_REV2;
|
||||
szForceROM = sizeof(ForceROM_REV2)/sizeof(*ForceROM);
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using OLD method\n"));
|
||||
} else {
|
||||
ForceROM = ForceROM_NEW;
|
||||
szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM);
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using NEW method\n"));
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Force Target to execute from ROM....\n"));
|
||||
for (i = 0; i < szForceROM; i++)
|
||||
{
|
||||
if (ar6000_WriteRegDiag(hifDevice,
|
||||
&ForceROM[i].addr,
|
||||
&ForceROM[i].data) != A_OK)
|
||||
{
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n"));
|
||||
return A_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
msleep(50); /* delay to allow dragon to come to BMI phase */
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
/* reset device */
|
||||
A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
|
||||
{
|
||||
|
||||
#if !defined(DWSIM)
|
||||
A_STATUS status = A_OK;
|
||||
A_UINT32 address;
|
||||
A_UINT32 data;
|
||||
|
||||
do {
|
||||
|
||||
// address = RESET_CONTROL_ADDRESS;
|
||||
data = RESET_CONTROL_COLD_RST_MASK;
|
||||
|
||||
/* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */
|
||||
if (TargetType == TARGET_TYPE_AR6001) {
|
||||
address = 0x0C000000;
|
||||
} else {
|
||||
if (TargetType == TARGET_TYPE_AR6002) {
|
||||
address = 0x00004000;
|
||||
} else {
|
||||
A_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
status = ar6000_WriteRegDiag(hifDevice, &address, &data);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read back the RESET CAUSE register to ensure that the cold reset
|
||||
* went through.
|
||||
*/
|
||||
msleep(2000); /* 2 second delay to allow things to settle down */
|
||||
|
||||
|
||||
// address = RESET_CAUSE_ADDRESS;
|
||||
/* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */
|
||||
if (TargetType == TARGET_TYPE_AR6001) {
|
||||
address = 0x0C0000CC;
|
||||
} else {
|
||||
if (TargetType == TARGET_TYPE_AR6002) {
|
||||
address = 0x000040C0;
|
||||
} else {
|
||||
A_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
data = 0;
|
||||
status = ar6000_ReadRegDiag(hifDevice, &address, &data);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data));
|
||||
data &= RESET_CAUSE_LAST_MASK;
|
||||
if (data != 2) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n"));
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n"));
|
||||
}
|
||||
#endif
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
#define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR6001_regdump.h */
|
||||
#define REG_DUMP_COUNT_AR6002 32 /* WORDs, derived from AR6002_regdump.h */
|
||||
|
||||
|
||||
#if REG_DUMP_COUNT_AR6001 <= REG_DUMP_COUNT_AR6002
|
||||
#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6002
|
||||
#else
|
||||
#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6001
|
||||
#endif
|
||||
|
||||
void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
|
||||
{
|
||||
A_UINT32 address;
|
||||
A_UINT32 regDumpArea = 0;
|
||||
A_STATUS status;
|
||||
A_UINT32 regDumpValues[REGISTER_DUMP_LEN_MAX];
|
||||
A_UINT32 regDumpCount = 0;
|
||||
A_UINT32 i;
|
||||
|
||||
do {
|
||||
|
||||
/* the reg dump pointer is copied to the host interest area */
|
||||
address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state);
|
||||
|
||||
if (TargetType == TARGET_TYPE_AR6001) {
|
||||
/* for AR6001, this is a fixed location because the ptr is actually stuck in cache,
|
||||
* this may be fixed in later firmware versions */
|
||||
address = 0x18a0;
|
||||
regDumpCount = REG_DUMP_COUNT_AR6001;
|
||||
|
||||
} else if (TargetType == TARGET_TYPE_AR6002) {
|
||||
|
||||
regDumpCount = REG_DUMP_COUNT_AR6002;
|
||||
|
||||
} else {
|
||||
A_ASSERT(0);
|
||||
}
|
||||
|
||||
/* read RAM location through diagnostic window */
|
||||
status = ar6000_ReadRegDiag(hifDevice, &address, ®DumpArea);
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea));
|
||||
|
||||
if (regDumpArea == 0) {
|
||||
/* no reg dump */
|
||||
break;
|
||||
}
|
||||
|
||||
if (TargetType == TARGET_TYPE_AR6001) {
|
||||
regDumpArea &= 0x0FFFFFFF; /* convert to physical address in target memory */
|
||||
}
|
||||
|
||||
/* fetch register dump data */
|
||||
status = ar6000_ReadDataDiag(hifDevice,
|
||||
regDumpArea,
|
||||
(A_UCHAR *)®DumpValues[0],
|
||||
regDumpCount * (sizeof(A_UINT32)));
|
||||
|
||||
if (A_FAILED(status)) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n"));
|
||||
break;
|
||||
}
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n"));
|
||||
|
||||
for (i = 0; i < regDumpCount; i++) {
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i]));
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004-2007 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include "a_debug.h"
|
||||
#include "htc_api.h"
|
||||
#include "common_drv.h"
|
||||
|
||||
/********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
|
||||
|
||||
#define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
|
||||
|
||||
#ifdef NO_VO_SERVICE
|
||||
#define DATA_SVCS_USED 3
|
||||
#else
|
||||
#define DATA_SVCS_USED 4
|
||||
#endif
|
||||
|
||||
static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
|
||||
|
||||
static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
|
||||
|
||||
/* reduce an ep's credits back to a set limit */
|
||||
static INLINE void ReduceCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEpDist,
|
||||
int Limit)
|
||||
{
|
||||
int credits;
|
||||
|
||||
/* set the new limit */
|
||||
pEpDist->TxCreditsAssigned = Limit;
|
||||
|
||||
if (pEpDist->TxCredits <= Limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* figure out how much to take away */
|
||||
credits = pEpDist->TxCredits - Limit;
|
||||
/* take them away */
|
||||
pEpDist->TxCredits -= credits;
|
||||
pCredInfo->CurrentFreeCredits += credits;
|
||||
}
|
||||
|
||||
/* give an endpoint some credits from the free credit pool */
|
||||
#define GiveCredits(pCredInfo,pEpDist,credits) \
|
||||
{ \
|
||||
(pEpDist)->TxCredits += (credits); \
|
||||
(pEpDist)->TxCreditsAssigned += (credits); \
|
||||
(pCredInfo)->CurrentFreeCredits -= (credits); \
|
||||
}
|
||||
|
||||
|
||||
/* default credit init callback.
|
||||
* This function is called in the context of HTCStart() to setup initial (application-specific)
|
||||
* credit distributions */
|
||||
static void ar6000_credit_init(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPList,
|
||||
int TotalCredits)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
|
||||
int count;
|
||||
COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
|
||||
|
||||
pCredInfo->CurrentFreeCredits = TotalCredits;
|
||||
pCredInfo->TotalAvailableCredits = TotalCredits;
|
||||
|
||||
pCurEpDist = pEPList;
|
||||
|
||||
/* run through the list and initialize */
|
||||
while (pCurEpDist != NULL) {
|
||||
|
||||
/* set minimums for each endpoint */
|
||||
pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
|
||||
|
||||
if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
|
||||
/* give control service some credits */
|
||||
GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
|
||||
/* control service is always marked active, it never goes inactive EVER */
|
||||
SET_EP_ACTIVE(pCurEpDist);
|
||||
} else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
|
||||
/* this is the lowest priority data endpoint, save this off for easy access */
|
||||
pCredInfo->pLowestPriEpDist = pCurEpDist;
|
||||
}
|
||||
|
||||
/* Streams have to be created (explicit | implicit)for all kinds
|
||||
* of traffic. BE endpoints are also inactive in the beginning.
|
||||
* When BE traffic starts it creates implicit streams that
|
||||
* redistributes credits.
|
||||
*/
|
||||
|
||||
/* note, all other endpoints have minimums set but are initially given NO credits.
|
||||
* Credits will be distributed as traffic activity demands */
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
|
||||
if (pCredInfo->CurrentFreeCredits <= 0) {
|
||||
AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
|
||||
A_ASSERT(FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset list */
|
||||
pCurEpDist = pEPList;
|
||||
/* now run through the list and set max operating credit limits for everyone */
|
||||
while (pCurEpDist != NULL) {
|
||||
if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
|
||||
/* control service max is just 1 max message */
|
||||
pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
|
||||
} else {
|
||||
/* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
|
||||
* the same.
|
||||
* We use a simple calculation here, we take the remaining credits and
|
||||
* determine how many max messages this can cover and then set each endpoint's
|
||||
* normal value equal to half this amount.
|
||||
* */
|
||||
count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
|
||||
count = count >> 1;
|
||||
count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
|
||||
/* set normal */
|
||||
pCurEpDist->TxCreditsNorm = count;
|
||||
|
||||
}
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* default credit distribution callback
|
||||
* This callback is invoked whenever endpoints require credit distributions.
|
||||
* A lock is held while this function is invoked, this function shall NOT block.
|
||||
* The pEPDistList is a list of distribution structures in prioritized order as
|
||||
* defined by the call to the HTCSetCreditDistribution() api.
|
||||
*
|
||||
*/
|
||||
static void ar6000_credit_distribute(void *Context,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
|
||||
HTC_CREDIT_DIST_REASON Reason)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
|
||||
COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
|
||||
|
||||
switch (Reason) {
|
||||
case HTC_CREDIT_DIST_SEND_COMPLETE :
|
||||
pCurEpDist = pEPDistList;
|
||||
/* we are given the start of the endpoint distribution list.
|
||||
* There may be one or more endpoints to service.
|
||||
* Run through the list and distribute credits */
|
||||
while (pCurEpDist != NULL) {
|
||||
|
||||
if (pCurEpDist->TxCreditsToDist > 0) {
|
||||
/* return the credits back to the endpoint */
|
||||
pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
|
||||
/* always zero out when we are done */
|
||||
pCurEpDist->TxCreditsToDist = 0;
|
||||
|
||||
if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
|
||||
/* reduce to the assigned limit, previous credit reductions
|
||||
* could have caused the limit to change */
|
||||
ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
|
||||
}
|
||||
|
||||
if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
|
||||
/* oversubscribed endpoints need to reduce back to normal */
|
||||
ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
|
||||
}
|
||||
}
|
||||
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
|
||||
A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
|
||||
|
||||
break;
|
||||
|
||||
case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
|
||||
RedistributeCredits(pCredInfo,pEPDistList);
|
||||
break;
|
||||
case HTC_CREDIT_DIST_SEEK_CREDITS :
|
||||
SeekCredits(pCredInfo,pEPDistList);
|
||||
break;
|
||||
case HTC_DUMP_CREDIT_STATE :
|
||||
AR_DEBUG_PRINTF(ATH_LOG_INF, ("Credit Distribution, total : %d, free : %d\n",
|
||||
pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* redistribute credits based on activity change */
|
||||
static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDistList)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist = pEPDistList;
|
||||
|
||||
/* walk through the list and remove credits from inactive endpoints */
|
||||
while (pCurEpDist != NULL) {
|
||||
|
||||
if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
|
||||
if (!IS_EP_ACTIVE(pCurEpDist)) {
|
||||
/* EP is inactive, reduce credits back to zero */
|
||||
ReduceCredits(pCredInfo, pCurEpDist, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE in the active case, we do not need to do anything further,
|
||||
* when an EP goes active and needs credits, HTC will call into
|
||||
* our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
|
||||
|
||||
pCurEpDist = pCurEpDist->pNext;
|
||||
}
|
||||
|
||||
A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
|
||||
|
||||
}
|
||||
|
||||
/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
|
||||
static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
|
||||
HTC_ENDPOINT_CREDIT_DIST *pEPDist)
|
||||
{
|
||||
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
|
||||
int credits = 0;
|
||||
int need;
|
||||
|
||||
do {
|
||||
|
||||
if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
|
||||
/* we never oversubscribe on the control service, this is not
|
||||
* a high performance path and the target never holds onto control
|
||||
* credits for too long */
|
||||
break;
|
||||
}
|
||||
|
||||
/* for all other services, we follow a simple algorithm of
|
||||
* 1. checking the free pool for credits
|
||||
* 2. checking lower priority endpoints for credits to take */
|
||||
|
||||
if (pCredInfo->CurrentFreeCredits >= 2 * pEPDist->TxCreditsSeek) {
|
||||
/* try to give more credits than it needs */
|
||||
credits = 2 * pEPDist->TxCreditsSeek;
|
||||
} else {
|
||||
/* give what we can */
|
||||
credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
|
||||
}
|
||||
|
||||
if (credits >= pEPDist->TxCreditsSeek) {
|
||||
/* we found some to fullfill the seek request */
|
||||
break;
|
||||
}
|
||||
|
||||
/* we don't have enough in the free pool, try taking away from lower priority services
|
||||
*
|
||||
* The rule for taking away credits:
|
||||
* 1. Only take from lower priority endpoints
|
||||
* 2. Only take what is allocated above the minimum (never starve an endpoint completely)
|
||||
* 3. Only take what you need.
|
||||
*
|
||||
* */
|
||||
|
||||
/* starting at the lowest priority */
|
||||
pCurEpDist = pCredInfo->pLowestPriEpDist;
|
||||
|
||||
/* work backwards until we hit the endpoint again */
|
||||
while (pCurEpDist != pEPDist) {
|
||||
/* calculate how many we need so far */
|
||||
need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
|
||||
|
||||
if ((pCurEpDist->TxCreditsAssigned - need) > pCurEpDist->TxCreditsMin) {
|
||||
/* the current one has been allocated more than it's minimum and it
|
||||
* has enough credits assigned above it's minimum to fullfill our need
|
||||
* try to take away just enough to fullfill our need */
|
||||
ReduceCredits(pCredInfo,
|
||||
pCurEpDist,
|
||||
pCurEpDist->TxCreditsAssigned - need);
|
||||
|
||||
if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
|
||||
/* we have enough */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pCurEpDist = pCurEpDist->pPrev;
|
||||
}
|
||||
|
||||
/* return what we can get */
|
||||
credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
/* did we find some credits? */
|
||||
if (credits) {
|
||||
/* give what we can */
|
||||
GiveCredits(pCredInfo, pEPDist, credits);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* initialize and setup credit distribution */
|
||||
A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo)
|
||||
{
|
||||
HTC_SERVICE_ID servicepriority[5];
|
||||
|
||||
A_MEMZERO(pCredInfo,sizeof(COMMON_CREDIT_STATE_INFO));
|
||||
|
||||
servicepriority[0] = WMI_CONTROL_SVC; /* highest */
|
||||
servicepriority[1] = WMI_DATA_VO_SVC;
|
||||
servicepriority[2] = WMI_DATA_VI_SVC;
|
||||
servicepriority[3] = WMI_DATA_BE_SVC;
|
||||
servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
|
||||
|
||||
/* set callbacks and priority list */
|
||||
HTCSetCreditDistribution(HTCHandle,
|
||||
pCredInfo,
|
||||
ar6000_credit_distribute,
|
||||
ar6000_credit_init,
|
||||
servicepriority,
|
||||
5);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,371 @@
|
|||
/*-
|
||||
* Copyright (c) 2001 Atsushi Onoe
|
||||
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
|
||||
* Copyright (c) 2004-2005 Atheros Communications
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/wlan/src/wlan_node.c#1 $
|
||||
*/
|
||||
/*
|
||||
* IEEE 802.11 node handling support.
|
||||
*/
|
||||
#include <a_config.h>
|
||||
#include <athdefs.h>
|
||||
#include <a_types.h>
|
||||
#include <a_osapi.h>
|
||||
#include <a_debug.h>
|
||||
#include <ieee80211.h>
|
||||
#include <wlan_api.h>
|
||||
#include <ieee80211_node.h>
|
||||
#include <htc_api.h>
|
||||
#include <wmi.h>
|
||||
#include <wmi_api.h>
|
||||
|
||||
static void wlan_node_timeout(A_ATH_TIMER arg);
|
||||
static bss_t * _ieee80211_find_node(struct ieee80211_node_table *nt,
|
||||
const A_UINT8 *macaddr);
|
||||
|
||||
bss_t *
|
||||
wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
|
||||
{
|
||||
bss_t *ni;
|
||||
|
||||
ni = A_MALLOC_NOWAIT(sizeof(bss_t));
|
||||
|
||||
if (ni != NULL) {
|
||||
ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
|
||||
if (ni->ni_buf == NULL) {
|
||||
A_FREE(ni);
|
||||
ni = NULL;
|
||||
return ni;
|
||||
}
|
||||
} else {
|
||||
return ni;
|
||||
}
|
||||
|
||||
/* Make sure our lists are clean */
|
||||
ni->ni_list_next = NULL;
|
||||
ni->ni_list_prev = NULL;
|
||||
ni->ni_hash_next = NULL;
|
||||
ni->ni_hash_prev = NULL;
|
||||
|
||||
//
|
||||
// ni_scangen never initialized before and during suspend/resume of winmobile, customer (LG/SEMCO) identified
|
||||
// that some junk has been stored in this, due to this scan list didn't properly updated
|
||||
//
|
||||
ni->ni_scangen = 0;
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
void
|
||||
wlan_node_free(bss_t *ni)
|
||||
{
|
||||
if (ni->ni_buf != NULL) {
|
||||
A_FREE(ni->ni_buf);
|
||||
}
|
||||
A_FREE(ni);
|
||||
}
|
||||
|
||||
void
|
||||
wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
|
||||
const A_UINT8 *macaddr)
|
||||
{
|
||||
int hash;
|
||||
|
||||
A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
|
||||
hash = IEEE80211_NODE_HASH(macaddr);
|
||||
ieee80211_node_initref(ni); /* mark referenced */
|
||||
|
||||
ni->ni_tstamp = A_GET_MS(WLAN_NODE_INACT_TIMEOUT_MSEC);
|
||||
IEEE80211_NODE_LOCK_BH(nt);
|
||||
|
||||
/* Insert at the end of the node list */
|
||||
ni->ni_list_next = NULL;
|
||||
ni->ni_list_prev = nt->nt_node_last;
|
||||
if(nt->nt_node_last != NULL)
|
||||
{
|
||||
nt->nt_node_last->ni_list_next = ni;
|
||||
}
|
||||
nt->nt_node_last = ni;
|
||||
if(nt->nt_node_first == NULL)
|
||||
{
|
||||
nt->nt_node_first = ni;
|
||||
}
|
||||
|
||||
/* Insert into the hash list i.e. the bucket */
|
||||
if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
|
||||
{
|
||||
nt->nt_hash[hash]->ni_hash_prev = ni;
|
||||
}
|
||||
ni->ni_hash_prev = NULL;
|
||||
nt->nt_hash[hash] = ni;
|
||||
|
||||
if (!nt->isTimerArmed) {
|
||||
A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
|
||||
nt->isTimerArmed = TRUE;
|
||||
}
|
||||
|
||||
IEEE80211_NODE_UNLOCK_BH(nt);
|
||||
}
|
||||
|
||||
static bss_t *
|
||||
_ieee80211_find_node(struct ieee80211_node_table *nt,
|
||||
const A_UINT8 *macaddr)
|
||||
{
|
||||
bss_t *ni;
|
||||
int hash;
|
||||
|
||||
IEEE80211_NODE_LOCK_ASSERT(nt);
|
||||
|
||||
hash = IEEE80211_NODE_HASH(macaddr);
|
||||
for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
|
||||
if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
|
||||
ieee80211_node_incref(ni); /* mark referenced */
|
||||
return ni;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bss_t *
|
||||
wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr)
|
||||
{
|
||||
bss_t *ni;
|
||||
|
||||
IEEE80211_NODE_LOCK(nt);
|
||||
ni = _ieee80211_find_node(nt, macaddr);
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
return ni;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim a node. If this is the last reference count then
|
||||
* do the normal free work. Otherwise remove it from the node
|
||||
* table and mark it gone by clearing the back-reference.
|
||||
*/
|
||||
void
|
||||
wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
|
||||
{
|
||||
IEEE80211_NODE_LOCK(nt);
|
||||
|
||||
if(ni->ni_list_prev == NULL)
|
||||
{
|
||||
/* First in list so fix the list head */
|
||||
nt->nt_node_first = ni->ni_list_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
ni->ni_list_prev->ni_list_next = ni->ni_list_next;
|
||||
}
|
||||
|
||||
if(ni->ni_list_next == NULL)
|
||||
{
|
||||
/* Last in list so fix list tail */
|
||||
nt->nt_node_last = ni->ni_list_prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
|
||||
}
|
||||
|
||||
if(ni->ni_hash_prev == NULL)
|
||||
{
|
||||
/* First in list so fix the list head */
|
||||
int hash;
|
||||
hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
|
||||
nt->nt_hash[hash] = ni->ni_hash_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
|
||||
}
|
||||
|
||||
if(ni->ni_hash_next != NULL)
|
||||
{
|
||||
ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
|
||||
}
|
||||
wlan_node_free(ni);
|
||||
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
}
|
||||
|
||||
static void
|
||||
wlan_node_dec_free(bss_t *ni)
|
||||
{
|
||||
if (ieee80211_node_dectestref(ni)) {
|
||||
wlan_node_free(ni);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wlan_free_allnodes(struct ieee80211_node_table *nt)
|
||||
{
|
||||
bss_t *ni;
|
||||
|
||||
while ((ni = nt->nt_node_first) != NULL) {
|
||||
wlan_node_reclaim(nt, ni);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
|
||||
void *arg)
|
||||
{
|
||||
bss_t *ni;
|
||||
A_UINT32 gen;
|
||||
|
||||
gen = ++nt->nt_scangen;
|
||||
|
||||
IEEE80211_NODE_LOCK(nt);
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
if (ni->ni_scangen != gen) {
|
||||
ni->ni_scangen = gen;
|
||||
(void) ieee80211_node_incref(ni);
|
||||
(*f)(arg, ni);
|
||||
wlan_node_dec_free(ni);
|
||||
}
|
||||
}
|
||||
IEEE80211_NODE_UNLOCK(nt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Node table support.
|
||||
*/
|
||||
void
|
||||
wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
|
||||
{
|
||||
int i;
|
||||
|
||||
AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%x\n", (A_UINT32)nt));
|
||||
IEEE80211_NODE_LOCK_INIT(nt);
|
||||
|
||||
nt->nt_node_first = nt->nt_node_last = NULL;
|
||||
for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
|
||||
{
|
||||
nt->nt_hash[i] = NULL;
|
||||
}
|
||||
A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
|
||||
nt->isTimerArmed = FALSE;
|
||||
nt->nt_wmip = wmip;
|
||||
}
|
||||
|
||||
static void
|
||||
wlan_node_timeout(A_ATH_TIMER arg)
|
||||
{
|
||||
struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg;
|
||||
bss_t *bss, *nextBss;
|
||||
A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE;
|
||||
|
||||
wmi_get_current_bssid(nt->nt_wmip, myBssid);
|
||||
|
||||
bss = nt->nt_node_first;
|
||||
while (bss != NULL)
|
||||
{
|
||||
nextBss = bss->ni_list_next;
|
||||
if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
|
||||
{
|
||||
|
||||
if (bss->ni_tstamp <= A_GET_MS(0))
|
||||
{
|
||||
/*
|
||||
* free up all but the current bss - if set
|
||||
*/
|
||||
wlan_node_reclaim(nt, bss);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Re-arm timer, only when we have a bss other than
|
||||
* current bss AND it is not aged-out.
|
||||
*/
|
||||
reArmTimer = TRUE;
|
||||
}
|
||||
}
|
||||
bss = nextBss;
|
||||
}
|
||||
|
||||
if(reArmTimer)
|
||||
A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
|
||||
|
||||
nt->isTimerArmed = reArmTimer;
|
||||
}
|
||||
|
||||
void
|
||||
wlan_node_table_cleanup(struct ieee80211_node_table *nt)
|
||||
{
|
||||
A_UNTIMEOUT(&nt->nt_inact_timer);
|
||||
A_DELETE_TIMER(&nt->nt_inact_timer);
|
||||
wlan_free_allnodes(nt);
|
||||
IEEE80211_NODE_LOCK_DESTROY(nt);
|
||||
}
|
||||
|
||||
bss_t *
|
||||
wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
|
||||
A_UINT32 ssidLength, A_BOOL bIsWPA2)
|
||||
{
|
||||
bss_t *ni = NULL;
|
||||
A_UCHAR *pIESsid = NULL;
|
||||
|
||||
IEEE80211_NODE_LOCK (nt);
|
||||
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
pIESsid = ni->ni_cie.ie_ssid;
|
||||
if (pIESsid[1] <= 32) {
|
||||
|
||||
// Step 1 : Check SSID
|
||||
if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
|
||||
|
||||
// Step 2 : if SSID matches, check WPA or WPA2
|
||||
if (TRUE == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) {
|
||||
ieee80211_node_incref (ni); /* mark referenced */
|
||||
IEEE80211_NODE_UNLOCK (nt);
|
||||
return ni;
|
||||
}
|
||||
if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
|
||||
ieee80211_node_incref(ni); /* mark referenced */
|
||||
IEEE80211_NODE_UNLOCK (nt);
|
||||
return ni;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEEE80211_NODE_UNLOCK (nt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
|
||||
{
|
||||
IEEE80211_NODE_LOCK (nt);
|
||||
wlan_node_dec_free (ni);
|
||||
IEEE80211_NODE_UNLOCK (nt);
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*-
|
||||
* Copyright (c) 2001 Atsushi Onoe
|
||||
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* IEEE 802.11 input handling.
|
||||
*/
|
||||
|
||||
#include "a_config.h"
|
||||
#include "athdefs.h"
|
||||
#include "a_types.h"
|
||||
#include "a_osapi.h"
|
||||
#include <wmi.h>
|
||||
#include <ieee80211.h>
|
||||
#include <wlan_api.h>
|
||||
|
||||
#define IEEE80211_VERIFY_LENGTH(_len, _minlen) do { \
|
||||
if ((_len) < (_minlen)) { \
|
||||
return A_EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do { \
|
||||
if ((__elem) == NULL) { \
|
||||
return A_EINVAL; \
|
||||
} \
|
||||
if ((__elem)[1] > (__maxlen)) { \
|
||||
return A_EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* unaligned little endian access */
|
||||
#define LE_READ_2(p) \
|
||||
((A_UINT16) \
|
||||
((((A_UINT8 *)(p))[0] ) | (((A_UINT8 *)(p))[1] << 8)))
|
||||
|
||||
#define LE_READ_4(p) \
|
||||
((A_UINT32) \
|
||||
((((A_UINT8 *)(p))[0] ) | (((A_UINT8 *)(p))[1] << 8) | \
|
||||
(((A_UINT8 *)(p))[2] << 16) | (((A_UINT8 *)(p))[3] << 24)))
|
||||
|
||||
|
||||
static int __inline
|
||||
iswpaoui(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
|
||||
}
|
||||
|
||||
static int __inline
|
||||
iswmmoui(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
|
||||
}
|
||||
|
||||
static int __inline
|
||||
iswmmparam(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
|
||||
}
|
||||
|
||||
static int __inline
|
||||
iswmminfo(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
|
||||
}
|
||||
|
||||
static int __inline
|
||||
isatherosoui(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
|
||||
}
|
||||
|
||||
static int __inline
|
||||
iswscoui(const A_UINT8 *frm)
|
||||
{
|
||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
wlan_parse_beacon(A_UINT8 *buf, int framelen, struct ieee80211_common_ie *cie)
|
||||
{
|
||||
A_UINT8 *frm, *efrm;
|
||||
|
||||
frm = buf;
|
||||
efrm = (A_UINT8 *) (frm + framelen);
|
||||
|
||||
/*
|
||||
* beacon/probe response frame format
|
||||
* [8] time stamp
|
||||
* [2] beacon interval
|
||||
* [2] capability information
|
||||
* [tlv] ssid
|
||||
* [tlv] supported rates
|
||||
* [tlv] country information
|
||||
* [tlv] parameter set (FH/DS)
|
||||
* [tlv] erp information
|
||||
* [tlv] extended supported rates
|
||||
* [tlv] WMM
|
||||
* [tlv] WPA or RSN
|
||||
* [tlv] Atheros Advanced Capabilities
|
||||
*/
|
||||
IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
|
||||
A_MEMZERO(cie, sizeof(*cie));
|
||||
|
||||
cie->ie_tstamp = frm; frm += 8;
|
||||
cie->ie_beaconInt = A_LE2CPU16(*(A_UINT16 *)frm); frm += 2;
|
||||
cie->ie_capInfo = A_LE2CPU16(*(A_UINT16 *)frm); frm += 2;
|
||||
cie->ie_chan = 0;
|
||||
|
||||
while (frm < efrm) {
|
||||
switch (*frm) {
|
||||
case IEEE80211_ELEMID_SSID:
|
||||
cie->ie_ssid = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_RATES:
|
||||
cie->ie_rates = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_COUNTRY:
|
||||
cie->ie_country = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_FHPARMS:
|
||||
break;
|
||||
case IEEE80211_ELEMID_DSPARMS:
|
||||
cie->ie_chan = frm[2];
|
||||
break;
|
||||
case IEEE80211_ELEMID_TIM:
|
||||
cie->ie_tim = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_IBSSPARMS:
|
||||
break;
|
||||
case IEEE80211_ELEMID_XRATES:
|
||||
cie->ie_xrates = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_ERP:
|
||||
if (frm[1] != 1) {
|
||||
//A_PRINTF("Discarding ERP Element - Bad Len\n");
|
||||
return A_EINVAL;
|
||||
}
|
||||
cie->ie_erp = frm[2];
|
||||
break;
|
||||
case IEEE80211_ELEMID_RSN:
|
||||
cie->ie_rsn = frm;
|
||||
break;
|
||||
case IEEE80211_ELEMID_VENDOR:
|
||||
if (iswpaoui(frm)) {
|
||||
cie->ie_wpa = frm;
|
||||
} else if (iswmmoui(frm)) {
|
||||
cie->ie_wmm = frm;
|
||||
} else if (isatherosoui(frm)) {
|
||||
cie->ie_ath = frm;
|
||||
} else if(iswscoui(frm)) {
|
||||
cie->ie_wsc = frm;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
frm += frm[1] + 2;
|
||||
}
|
||||
IEEE80211_VERIFY_ELEMENT(cie->ie_rates, IEEE80211_RATE_MAXSIZE);
|
||||
IEEE80211_VERIFY_ELEMENT(cie->ie_ssid, IEEE80211_NWID_LEN);
|
||||
|
||||
return A_OK;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This module implements frequently used wlan utilies
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/wlan/src/wlan_utils.c#1 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <a_config.h>
|
||||
#include <athdefs.h>
|
||||
#include <a_types.h>
|
||||
#include <a_osapi.h>
|
||||
|
||||
/*
|
||||
* converts ieee channel number to frequency
|
||||
*/
|
||||
A_UINT16
|
||||
wlan_ieee2freq(int chan)
|
||||
{
|
||||
if (chan == 14) {
|
||||
return 2484;
|
||||
}
|
||||
if (chan < 14) { /* 0-13 */
|
||||
return (2407 + (chan*5));
|
||||
}
|
||||
if (chan < 27) { /* 15-26 */
|
||||
return (2512 + ((chan-15)*20));
|
||||
}
|
||||
return (5000 + (chan*5));
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts MHz frequency to IEEE channel number.
|
||||
*/
|
||||
A_UINT32
|
||||
wlan_freq2ieee(A_UINT16 freq)
|
||||
{
|
||||
if (freq == 2484)
|
||||
return 14;
|
||||
if (freq < 2484)
|
||||
return (freq - 2407) / 5;
|
||||
if (freq < 5000)
|
||||
return 15 + ((freq - 2512) / 20);
|
||||
return (freq - 5000) / 5;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,71 @@
|
|||
#ifndef _WMI_HOST_H_
|
||||
#define _WMI_HOST_H_
|
||||
/*
|
||||
* Copyright (c) 2004-2006 Atheros Communications Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file contains local definitios for the wmi host module.
|
||||
*
|
||||
* $Id: //depot/sw/releases/olca2.0-GPL/host/wmi/wmi_host.h#1 $
|
||||
*
|
||||
*
|
||||
* 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;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct wmi_stats {
|
||||
A_UINT32 cmd_len_err;
|
||||
A_UINT32 cmd_id_err;
|
||||
};
|
||||
|
||||
struct wmi_t {
|
||||
A_BOOL wmi_ready;
|
||||
A_BOOL wmi_numQoSStream;
|
||||
A_UINT8 wmi_wmiStream2AcMapping[WMI_PRI_MAX_COUNT];
|
||||
WMI_PRI_STREAM_ID wmi_ac2WmiStreamMapping[WMM_NUM_AC];
|
||||
A_UINT16 wmi_streamExistsForAC[WMM_NUM_AC];
|
||||
A_UINT8 wmi_fatPipeExists;
|
||||
void *wmi_devt;
|
||||
struct wmi_stats wmi_stats;
|
||||
struct ieee80211_node_table wmi_scan_table;
|
||||
A_UINT8 wmi_bssid[ATH_MAC_LEN];
|
||||
A_UINT8 wmi_powerMode;
|
||||
A_UINT8 wmi_phyMode;
|
||||
A_UINT8 wmi_keepaliveInterval;
|
||||
A_MUTEX_T wmi_lock;
|
||||
};
|
||||
|
||||
#define WMI_INIT_WMISTREAM_AC_MAP(w) \
|
||||
{ (w)->wmi_wmiStream2AcMapping[WMI_BEST_EFFORT_PRI] = WMM_AC_BE; \
|
||||
(w)->wmi_wmiStream2AcMapping[WMI_LOW_PRI] = WMM_AC_BK; \
|
||||
(w)->wmi_wmiStream2AcMapping[WMI_HIGH_PRI] = WMM_AC_VI; \
|
||||
(w)->wmi_wmiStream2AcMapping[WMI_HIGHEST_PRI] = WMM_AC_VO; \
|
||||
(w)->wmi_ac2WmiStreamMapping[WMM_AC_BE] = WMI_BEST_EFFORT_PRI; \
|
||||
(w)->wmi_ac2WmiStreamMapping[WMM_AC_BK] = WMI_LOW_PRI; \
|
||||
(w)->wmi_ac2WmiStreamMapping[WMM_AC_VI] = WMI_HIGH_PRI; \
|
||||
(w)->wmi_ac2WmiStreamMapping[WMM_AC_VO] = WMI_HIGHEST_PRI; }
|
||||
|
||||
#define WMI_WMISTREAM_ACCESSCATEGORY(w,s) (w)->wmi_wmiStream2AcMapping[s]
|
||||
#define WMI_ACCESSCATEGORY_WMISTREAM(w,ac) (w)->wmi_ac2WmiStreamMapping[ac]
|
||||
|
||||
#define LOCK_WMI(w) A_MUTEX_LOCK(&(w)->wmi_lock);
|
||||
#define UNLOCK_WMI(w) A_MUTEX_UNLOCK(&(w)->wmi_lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _WMI_HOST_H_ */
|
|
@ -0,0 +1,932 @@
|
|||
/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
|
||||
*
|
||||
* Copyright (C) 2007-2008 by Openmoko, Inc.
|
||||
* Author: Harald Welte <laforge@openmoko.org>
|
||||
* converted to private bitbang by:
|
||||
* Andy Green <andy@openmoko.com>
|
||||
* ability to set acceleration threshold added by:
|
||||
* Simon Kagstrom <simon.kagstrom@gmail.com>
|
||||
* All rights reserved.
|
||||
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* TODO
|
||||
* * statistics for overflow events
|
||||
* * configuration interface (sysfs) for
|
||||
* * enable/disable x/y/z axis data ready
|
||||
* * enable/disable resume from freee fall / click
|
||||
* * free fall / click parameters
|
||||
* * high pass filter parameters
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/lis302dl.h>
|
||||
|
||||
static uint8_t lis_reg_read(struct lis302dl_info *lis, uint8_t reg)
|
||||
{
|
||||
return spi_w8r8(lis->spi, 0xc0 | reg);
|
||||
}
|
||||
|
||||
static void lis_reg_write(struct lis302dl_info *lis, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t data[2] = {reg, val};
|
||||
|
||||
spi_write(lis->spi, data, sizeof(data));
|
||||
}
|
||||
|
||||
static void lis_reg_set_bit_mask(struct lis302dl_info *lis, uint8_t reg, uint8_t mask,
|
||||
uint8_t val)
|
||||
{
|
||||
uint8_t tmp;
|
||||
|
||||
val &= mask;
|
||||
|
||||
tmp = lis_reg_read(lis, reg);
|
||||
tmp &= ~mask;
|
||||
tmp |= val;
|
||||
lis_reg_write(lis, reg, tmp);
|
||||
}
|
||||
|
||||
static int __ms_to_duration(struct lis302dl_info *lis, int ms)
|
||||
{
|
||||
/* If we have 400 ms sampling rate, the stepping is 2.5 ms,
|
||||
* on 100 ms the stepping is 10ms */
|
||||
if (lis->flags & LIS302DL_F_DR)
|
||||
return min((ms * 10) / 25, 637);
|
||||
|
||||
return min(ms / 10, 2550);
|
||||
}
|
||||
|
||||
static int __duration_to_ms(struct lis302dl_info *lis, int duration)
|
||||
{
|
||||
if (lis->flags & LIS302DL_F_DR)
|
||||
return (duration * 25) / 10;
|
||||
|
||||
return duration * 10;
|
||||
}
|
||||
|
||||
static uint8_t __mg_to_threshold(struct lis302dl_info *lis, int mg)
|
||||
{
|
||||
/* If FS is set each bit is 71mg, otherwise 18mg. The THS register
|
||||
* has 7 bits for the threshold value */
|
||||
if (lis->flags & LIS302DL_F_FS)
|
||||
return min(mg / 71, 127);
|
||||
|
||||
return min(mg / 18, 127);
|
||||
}
|
||||
|
||||
static int __threshold_to_mg(struct lis302dl_info *lis, uint8_t threshold)
|
||||
{
|
||||
if (lis->flags & LIS302DL_F_FS)
|
||||
return threshold * 71;
|
||||
|
||||
return threshold * 18;
|
||||
}
|
||||
|
||||
/* interrupt handling related */
|
||||
|
||||
enum lis302dl_intmode {
|
||||
LIS302DL_INTMODE_GND = 0x00,
|
||||
LIS302DL_INTMODE_FF_WU_1 = 0x01,
|
||||
LIS302DL_INTMODE_FF_WU_2 = 0x02,
|
||||
LIS302DL_INTMODE_FF_WU_12 = 0x03,
|
||||
LIS302DL_INTMODE_DATA_READY = 0x04,
|
||||
LIS302DL_INTMODE_CLICK = 0x07,
|
||||
};
|
||||
|
||||
static void lis302dl_set_int_mode(struct device *dev, int int_pin,
|
||||
enum lis302dl_intmode mode)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
switch (int_pin) {
|
||||
case 1:
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
|
||||
break;
|
||||
case 2:
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static void __enable_wakeup(struct lis302dl_info *lis)
|
||||
{
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, 0);
|
||||
|
||||
/* First zero to get to a known state */
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
|
||||
LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE |
|
||||
LIS302DL_FFWUCFG_LIR);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
|
||||
__mg_to_threshold(lis, lis->wakeup.threshold));
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
|
||||
__ms_to_duration(lis, lis->wakeup.duration));
|
||||
|
||||
/* Route the interrupt for wakeup */
|
||||
lis302dl_set_int_mode(lis->dev, 1,
|
||||
LIS302DL_INTMODE_FF_WU_1);
|
||||
|
||||
lis_reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
|
||||
lis_reg_read(lis, LIS302DL_REG_OUT_X);
|
||||
lis_reg_read(lis, LIS302DL_REG_OUT_Y);
|
||||
lis_reg_read(lis, LIS302DL_REG_OUT_Z);
|
||||
lis_reg_read(lis, LIS302DL_REG_STATUS);
|
||||
lis_reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
|
||||
lis_reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
|
||||
}
|
||||
|
||||
static void __enable_data_collection(struct lis302dl_info *lis)
|
||||
{
|
||||
u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
|
||||
LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
|
||||
|
||||
/* make sure we're powered up and generate data ready */
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
|
||||
|
||||
/* If the threshold is zero, let the device generated an interrupt
|
||||
* on each datum */
|
||||
if (lis->threshold == 0) {
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL2, 0);
|
||||
lis302dl_set_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
|
||||
lis302dl_set_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
|
||||
} else {
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL2,
|
||||
LIS302DL_CTRL2_HPFF1);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
|
||||
__mg_to_threshold(lis, lis->threshold));
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
|
||||
__ms_to_duration(lis, lis->duration));
|
||||
|
||||
/* Clear the HP filter "starting point" */
|
||||
lis_reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
|
||||
LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE |
|
||||
LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR);
|
||||
lis302dl_set_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12);
|
||||
lis302dl_set_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void _report_btn_single(struct input_dev *inp, int btn)
|
||||
{
|
||||
input_report_key(inp, btn, 1);
|
||||
input_sync(inp);
|
||||
input_report_key(inp, btn, 0);
|
||||
}
|
||||
|
||||
static void _report_btn_double(struct input_dev *inp, int btn)
|
||||
{
|
||||
input_report_key(inp, btn, 1);
|
||||
input_sync(inp);
|
||||
input_report_key(inp, btn, 0);
|
||||
input_sync(inp);
|
||||
input_report_key(inp, btn, 1);
|
||||
input_sync(inp);
|
||||
input_report_key(inp, btn, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
|
||||
{
|
||||
uint8_t data[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 2] = {0xC0 | LIS302DL_REG_STATUS};
|
||||
uint8_t *read = data + 1;
|
||||
unsigned long flags;
|
||||
int mg_per_sample = __threshold_to_mg(lis, 1);
|
||||
struct spi_message msg;
|
||||
struct spi_transfer t;
|
||||
|
||||
spi_message_init(&msg);
|
||||
memset(&t, 0, sizeof t);
|
||||
t.len = sizeof(data);
|
||||
spi_message_add_tail(&t, &msg);
|
||||
t.tx_buf = &data[0];
|
||||
t.rx_buf = &data[0];
|
||||
|
||||
/* grab the set of register containing status and XYZ data */
|
||||
local_irq_save(flags);
|
||||
/* Should complete without blocking */
|
||||
if (spi_sync(lis->spi, &msg) < 0)
|
||||
dev_err(lis->dev, "Error reading registers\n");
|
||||
|
||||
local_irq_restore(flags);
|
||||
/*
|
||||
* at the minute the test below fails 50% of the time due to
|
||||
* a problem with level interrupts causing ISRs to get called twice.
|
||||
* This is a workaround for that, but actually this test is still
|
||||
* valid and the information can be used for overrrun stats.
|
||||
*/
|
||||
|
||||
/* has any kind of overrun been observed by the lis302dl? */
|
||||
if (read[0] & (LIS302DL_STATUS_XOR |
|
||||
LIS302DL_STATUS_YOR |
|
||||
LIS302DL_STATUS_ZOR))
|
||||
lis->overruns++;
|
||||
|
||||
/* we have a valid sample set? */
|
||||
if (read[0] & LIS302DL_STATUS_XYZDA) {
|
||||
input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
|
||||
(s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
|
||||
input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
|
||||
(s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
|
||||
input_report_abs(lis->input_dev, ABS_Z, mg_per_sample *
|
||||
(s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
|
||||
|
||||
input_sync(lis->input_dev);
|
||||
} else {
|
||||
printk("invalid sample\n");
|
||||
}
|
||||
|
||||
if (lis->threshold)
|
||||
/* acknowledge the wakeup source */
|
||||
lis_reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
|
||||
enable_irq(lis->pdata->interrupt);
|
||||
}
|
||||
|
||||
static void lis302dl_irq_worker(struct work_struct *work) {
|
||||
struct lis302dl_info *lis = container_of(work, struct lis302dl_info, work);
|
||||
lis302dl_bitbang_read_sample(lis);
|
||||
}
|
||||
|
||||
static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
|
||||
{
|
||||
struct lis302dl_info *lis = _lis;
|
||||
disable_irq_nosync(lis->pdata->interrupt);
|
||||
schedule_work(&lis->work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* sysfs */
|
||||
|
||||
static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", lis->overruns);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL);
|
||||
|
||||
static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
uint8_t ctrl1;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
ctrl1 = lis_reg_read(lis, LIS302DL_REG_CTRL1);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
|
||||
}
|
||||
|
||||
static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (!strcmp(buf, "400\n")) {
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
|
||||
LIS302DL_CTRL1_DR);
|
||||
lis->flags |= LIS302DL_F_DR;
|
||||
} else {
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
|
||||
0);
|
||||
lis->flags &= ~LIS302DL_F_DR;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
|
||||
|
||||
static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
u_int8_t ctrl1;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
ctrl1 = lis_reg_read(lis, LIS302DL_REG_CTRL1);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
|
||||
}
|
||||
|
||||
static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (!strcmp(buf, "9.2\n")) {
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
|
||||
LIS302DL_CTRL1_FS);
|
||||
lis->flags |= LIS302DL_F_FS;
|
||||
} else {
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
|
||||
0);
|
||||
lis->flags &= ~LIS302DL_F_FS;
|
||||
}
|
||||
|
||||
if (lis->flags & LIS302DL_F_INPUT_OPEN)
|
||||
__enable_data_collection(lis);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
|
||||
|
||||
static ssize_t show_threshold(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
|
||||
/* Display the device view of the threshold setting */
|
||||
return sprintf(buf, "%d\n", __threshold_to_mg(lis,
|
||||
__mg_to_threshold(lis, lis->threshold)));
|
||||
}
|
||||
|
||||
static ssize_t set_threshold(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
|
||||
if (sscanf(buf, "%u\n", &val) != 1)
|
||||
return -EINVAL;
|
||||
/* 8g is the maximum if FS is 1 */
|
||||
if (val > 8000)
|
||||
return -ERANGE;
|
||||
|
||||
/* Set the threshold and write it out if the device is used */
|
||||
lis->threshold = val;
|
||||
|
||||
if (lis->flags & LIS302DL_F_INPUT_OPEN) {
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
__enable_data_collection(lis);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold);
|
||||
|
||||
static ssize_t show_duration(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", __duration_to_ms(lis,
|
||||
__ms_to_duration(lis, lis->duration)));
|
||||
}
|
||||
|
||||
static ssize_t set_duration(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
|
||||
if (sscanf(buf, "%u\n", &val) != 1)
|
||||
return -EINVAL;
|
||||
if (val > 2550)
|
||||
return -ERANGE;
|
||||
|
||||
lis->duration = val;
|
||||
if (lis->flags & LIS302DL_F_INPUT_OPEN)
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
|
||||
__ms_to_duration(lis, lis->duration));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration);
|
||||
|
||||
static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
int n = 0;
|
||||
uint8_t reg[0x40];
|
||||
char *end = buf;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (n = 0; n < sizeof(reg); n++)
|
||||
reg[n] = lis_reg_read(lis, n);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
for (n = 0; n < sizeof(reg); n += 16) {
|
||||
hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
|
||||
end += strlen(end);
|
||||
*end++ = '\n';
|
||||
*end++ = '\0';
|
||||
}
|
||||
|
||||
return end - buf;
|
||||
}
|
||||
static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
|
||||
|
||||
/* Configure freefall/wakeup interrupts */
|
||||
static ssize_t set_wakeup_threshold(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned int threshold;
|
||||
|
||||
if (sscanf(buf, "%u\n", &threshold) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (threshold > 8000)
|
||||
return -ERANGE;
|
||||
|
||||
/* Zero turns the feature off */
|
||||
if (threshold == 0) {
|
||||
if (lis->flags & LIS302DL_F_IRQ_WAKE) {
|
||||
disable_irq_wake(lis->pdata->interrupt);
|
||||
lis->flags &= ~LIS302DL_F_IRQ_WAKE;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
lis->wakeup.threshold = threshold;
|
||||
|
||||
if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
|
||||
enable_irq_wake(lis->pdata->interrupt);
|
||||
lis->flags |= LIS302DL_F_IRQ_WAKE;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_wakeup_threshold(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
|
||||
/* All events off? */
|
||||
if (lis->wakeup.threshold == 0)
|
||||
return sprintf(buf, "off\n");
|
||||
|
||||
return sprintf(buf, "%u\n", lis->wakeup.threshold);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold,
|
||||
set_wakeup_threshold);
|
||||
|
||||
static ssize_t set_wakeup_duration(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
unsigned int duration;
|
||||
|
||||
if (sscanf(buf, "%u\n", &duration) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (duration > 2550)
|
||||
return -ERANGE;
|
||||
|
||||
lis->wakeup.duration = duration;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_wakeup_duration(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", lis->wakeup.duration);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration,
|
||||
set_wakeup_duration);
|
||||
|
||||
static struct attribute *lis302dl_sysfs_entries[] = {
|
||||
&dev_attr_sample_rate.attr,
|
||||
&dev_attr_full_scale.attr,
|
||||
&dev_attr_threshold.attr,
|
||||
&dev_attr_duration.attr,
|
||||
&dev_attr_dump.attr,
|
||||
&dev_attr_wakeup_threshold.attr,
|
||||
&dev_attr_wakeup_duration.attr,
|
||||
&dev_attr_overruns.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group lis302dl_attr_group = {
|
||||
.name = NULL,
|
||||
.attrs = lis302dl_sysfs_entries,
|
||||
};
|
||||
|
||||
/* input device handling and driver core interaction */
|
||||
|
||||
static int lis302dl_input_open(struct input_dev *inp)
|
||||
{
|
||||
struct lis302dl_info *lis = input_get_drvdata(inp);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
__enable_data_collection(lis);
|
||||
lis->flags |= LIS302DL_F_INPUT_OPEN;
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lis302dl_input_close(struct input_dev *inp)
|
||||
{
|
||||
struct lis302dl_info *lis = input_get_drvdata(inp);
|
||||
u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
|
||||
LIS302DL_CTRL1_Zen;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* since the input core already serializes access and makes sure we
|
||||
* only see close() for the close of the last user, we can safely
|
||||
* disable the data ready events */
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
|
||||
lis->flags &= ~LIS302DL_F_INPUT_OPEN;
|
||||
|
||||
/* however, don't power down the whole device if still needed */
|
||||
if (!(lis->flags & LIS302DL_F_WUP_FF ||
|
||||
lis->flags & LIS302DL_F_WUP_CLICK)) {
|
||||
lis_reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
|
||||
0x00);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* get the device to reload its coefficients from EEPROM and wait for it
|
||||
* to complete
|
||||
*/
|
||||
|
||||
static int __lis302dl_reset_device(struct lis302dl_info *lis)
|
||||
{
|
||||
int timeout = 10;
|
||||
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL2,
|
||||
LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
|
||||
|
||||
while ((lis_reg_read(lis, LIS302DL_REG_CTRL2)
|
||||
& LIS302DL_CTRL2_BOOT) && (timeout--))
|
||||
mdelay(1);
|
||||
|
||||
return !!(timeout < 0);
|
||||
}
|
||||
|
||||
static int __devinit lis302dl_probe(struct spi_device *spi)
|
||||
{
|
||||
int rc;
|
||||
struct lis302dl_info *lis;
|
||||
u_int8_t wai;
|
||||
unsigned long flags;
|
||||
struct lis302dl_platform_data *pdata = spi->dev.platform_data;
|
||||
|
||||
spi->mode = SPI_MODE_3;
|
||||
rc = spi_setup(spi);
|
||||
if (rc < 0) {
|
||||
dev_err(&spi->dev, "spi_setup failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
lis = kzalloc(sizeof(*lis), GFP_KERNEL);
|
||||
if (!lis)
|
||||
return -ENOMEM;
|
||||
|
||||
lis->dev = &spi->dev;
|
||||
lis->spi = spi;
|
||||
|
||||
dev_set_drvdata(lis->dev, lis);
|
||||
|
||||
lis->pdata = pdata;
|
||||
|
||||
rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
|
||||
if (rc) {
|
||||
dev_err(lis->dev, "error creating sysfs group\n");
|
||||
goto bail_free_lis;
|
||||
}
|
||||
|
||||
/* initialize input layer details */
|
||||
lis->input_dev = input_allocate_device();
|
||||
if (!lis->input_dev) {
|
||||
dev_err(lis->dev, "Unable to allocate input device\n");
|
||||
goto bail_sysfs;
|
||||
}
|
||||
|
||||
input_set_drvdata(lis->input_dev, lis);
|
||||
lis->input_dev->name = pdata->name;
|
||||
/* SPI Bus not defined as a valid bus for input subsystem*/
|
||||
lis->input_dev->id.bustype = BUS_I2C; /* lie about it */
|
||||
lis->input_dev->open = lis302dl_input_open;
|
||||
lis->input_dev->close = lis302dl_input_close;
|
||||
|
||||
rc = input_register_device(lis->input_dev);
|
||||
if (rc) {
|
||||
dev_err(lis->dev, "error %d registering input device\n", rc);
|
||||
goto bail_inp_dev;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
/* Configure our IO */
|
||||
(lis->pdata->lis302dl_suspend_io)(lis, 1);
|
||||
|
||||
wai = lis_reg_read(lis, LIS302DL_REG_WHO_AM_I);
|
||||
if (wai != LIS302DL_WHO_AM_I_MAGIC) {
|
||||
dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
|
||||
dev_set_drvdata(lis->dev, NULL);
|
||||
rc = -ENODEV;
|
||||
local_irq_restore(flags);
|
||||
goto bail_inp_reg;
|
||||
}
|
||||
|
||||
set_bit(EV_ABS, lis->input_dev->evbit);
|
||||
input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0);
|
||||
input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0);
|
||||
input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0);
|
||||
|
||||
lis->threshold = 0;
|
||||
lis->duration = 0;
|
||||
memset(&lis->wakeup, 0, sizeof(lis->wakeup));
|
||||
|
||||
if (__lis302dl_reset_device(lis))
|
||||
dev_err(lis->dev, "device BOOT reload failed\n");
|
||||
|
||||
/* force us powered */
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
|
||||
LIS302DL_CTRL1_Xen |
|
||||
LIS302DL_CTRL1_Yen |
|
||||
LIS302DL_CTRL1_Zen);
|
||||
mdelay(1);
|
||||
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL2, 0);
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL3,
|
||||
LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
|
||||
lis_reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0);
|
||||
|
||||
/* start off in powered down mode; we power up when someone opens us */
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
|
||||
LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen);
|
||||
|
||||
if (pdata->open_drain)
|
||||
/* switch interrupt to open collector, active-low */
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL3,
|
||||
LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
|
||||
else
|
||||
/* push-pull, active-low */
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
|
||||
|
||||
lis302dl_set_int_mode(lis->dev, 1, LIS302DL_INTMODE_GND);
|
||||
lis302dl_set_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND);
|
||||
|
||||
lis_reg_read(lis, LIS302DL_REG_STATUS);
|
||||
lis_reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
|
||||
lis_reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
|
||||
lis_reg_read(lis, LIS302DL_REG_CLICK_SRC);
|
||||
local_irq_restore(flags);
|
||||
|
||||
dev_info(lis->dev, "Found %s\n", pdata->name);
|
||||
|
||||
lis->pdata = pdata;
|
||||
|
||||
INIT_WORK(&lis->work, lis302dl_irq_worker);
|
||||
|
||||
set_irq_handler(lis->pdata->interrupt, handle_level_irq);
|
||||
set_irq_type(lis->pdata->interrupt, IRQ_TYPE_LEVEL_LOW);
|
||||
rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt,
|
||||
IRQF_TRIGGER_FALLING, "lis302dl", lis);
|
||||
|
||||
if (rc < 0) {
|
||||
dev_err(lis->dev, "error requesting IRQ %d\n",
|
||||
lis->pdata->interrupt);
|
||||
goto bail_inp_reg;
|
||||
}
|
||||
return 0;
|
||||
|
||||
bail_inp_reg:
|
||||
input_unregister_device(lis->input_dev);
|
||||
bail_inp_dev:
|
||||
input_free_device(lis->input_dev);
|
||||
bail_sysfs:
|
||||
sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group);
|
||||
bail_free_lis:
|
||||
kfree(lis);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit lis302dl_remove(struct spi_device *spi)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||||
unsigned long flags;
|
||||
|
||||
/* Disable interrupts */
|
||||
if (lis->flags & LIS302DL_F_IRQ_WAKE)
|
||||
disable_irq_wake(lis->pdata->interrupt);
|
||||
free_irq(lis->pdata->interrupt, lis);
|
||||
|
||||
/* Reset and power down the device */
|
||||
local_irq_save(flags);
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Cleanup resources */
|
||||
sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
|
||||
input_unregister_device(lis->input_dev);
|
||||
if (lis->input_dev)
|
||||
input_free_device(lis->input_dev);
|
||||
dev_set_drvdata(lis->dev, NULL);
|
||||
kfree(lis);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static uint8_t regs_to_save[] = {
|
||||
LIS302DL_REG_CTRL1,
|
||||
LIS302DL_REG_CTRL2,
|
||||
LIS302DL_REG_CTRL3,
|
||||
LIS302DL_REG_FF_WU_CFG_1,
|
||||
LIS302DL_REG_FF_WU_THS_1,
|
||||
LIS302DL_REG_FF_WU_DURATION_1,
|
||||
LIS302DL_REG_FF_WU_CFG_2,
|
||||
LIS302DL_REG_FF_WU_THS_2,
|
||||
LIS302DL_REG_FF_WU_DURATION_2,
|
||||
LIS302DL_REG_CLICK_CFG,
|
||||
LIS302DL_REG_CLICK_THSY_X,
|
||||
LIS302DL_REG_CLICK_THSZ,
|
||||
LIS302DL_REG_CLICK_TIME_LIMIT,
|
||||
LIS302DL_REG_CLICK_LATENCY,
|
||||
LIS302DL_REG_CLICK_WINDOW,
|
||||
|
||||
};
|
||||
|
||||
static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||||
unsigned long flags;
|
||||
u_int8_t tmp;
|
||||
int n;
|
||||
|
||||
/* determine if we want to wake up from the accel. */
|
||||
if (lis->flags & LIS302DL_F_WUP_CLICK)
|
||||
return 0;
|
||||
|
||||
disable_irq(lis->pdata->interrupt);
|
||||
local_irq_save(flags);
|
||||
|
||||
/*
|
||||
* When we share SPI over multiple sensors, there is a race here
|
||||
* that one or more sensors will lose. In that case, the shared
|
||||
* SPI bus GPIO will be in sleep mode and partially pulled down. So
|
||||
* we explicitly put our IO into "wake" mode here before the final
|
||||
* traffic to the sensor.
|
||||
*/
|
||||
(lis->pdata->lis302dl_suspend_io)(lis, 1);
|
||||
|
||||
/* save registers */
|
||||
for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
|
||||
lis->regs[regs_to_save[n]] =
|
||||
lis_reg_read(lis, regs_to_save[n]);
|
||||
|
||||
/* power down or enable wakeup */
|
||||
|
||||
if (lis->wakeup.threshold == 0) {
|
||||
tmp = lis_reg_read(lis, LIS302DL_REG_CTRL1);
|
||||
tmp &= ~LIS302DL_CTRL1_PD;
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1, tmp);
|
||||
} else
|
||||
__enable_wakeup(lis);
|
||||
|
||||
/* place our IO to the device in sleep-compatible states */
|
||||
(lis->pdata->lis302dl_suspend_io)(lis, 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis302dl_resume(struct spi_device *spi)
|
||||
{
|
||||
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||||
unsigned long flags;
|
||||
int n;
|
||||
|
||||
if (lis->flags & LIS302DL_F_WUP_CLICK)
|
||||
return 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* get our IO to the device back in operational states */
|
||||
(lis->pdata->lis302dl_suspend_io)(lis, 1);
|
||||
|
||||
/* resume from powerdown first! */
|
||||
lis_reg_write(lis, LIS302DL_REG_CTRL1,
|
||||
LIS302DL_CTRL1_PD |
|
||||
LIS302DL_CTRL1_Xen |
|
||||
LIS302DL_CTRL1_Yen |
|
||||
LIS302DL_CTRL1_Zen);
|
||||
mdelay(1);
|
||||
|
||||
if (__lis302dl_reset_device(lis))
|
||||
dev_err(&spi->dev, "device BOOT reload failed\n");
|
||||
|
||||
lis->regs[LIS302DL_REG_CTRL1] |= LIS302DL_CTRL1_PD |
|
||||
LIS302DL_CTRL1_Xen |
|
||||
LIS302DL_CTRL1_Yen |
|
||||
LIS302DL_CTRL1_Zen;
|
||||
|
||||
/* restore registers after resume */
|
||||
for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
|
||||
lis_reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]);
|
||||
|
||||
/* if someone had us open, reset the non-wake threshold stuff */
|
||||
if (lis->flags & LIS302DL_F_INPUT_OPEN)
|
||||
__enable_data_collection(lis);
|
||||
|
||||
local_irq_restore(flags);
|
||||
enable_irq(lis->pdata->interrupt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define lis302dl_suspend NULL
|
||||
#define lis302dl_resume NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver lis302dl_spi_driver = {
|
||||
.driver = {
|
||||
.name = "lis302dl",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
||||
.probe = lis302dl_probe,
|
||||
.remove = __devexit_p(lis302dl_remove),
|
||||
.suspend = lis302dl_suspend,
|
||||
.resume = lis302dl_resume,
|
||||
};
|
||||
|
||||
static int __devinit lis302dl_init(void)
|
||||
{
|
||||
return spi_register_driver(&lis302dl_spi_driver);
|
||||
}
|
||||
module_init(lis302dl_init);
|
||||
|
||||
static void __exit lis302dl_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&lis302dl_spi_driver);
|
||||
}
|
||||
module_exit(lis302dl_exit);
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,593 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
* iPAQ H1940 touchscreen support
|
||||
*
|
||||
* ChangeLog
|
||||
*
|
||||
* 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
|
||||
* - added clock (de-)allocation code
|
||||
*
|
||||
* 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
* - h1940_ -> s3c2410 (this driver is now also used on the n30
|
||||
* machines :P)
|
||||
* - Debug messages are now enabled with the config option
|
||||
* TOUCHSCREEN_S3C2410_DEBUG
|
||||
* - Changed the way the value are read
|
||||
* - Input subsystem should now work
|
||||
* - Use ioremap and readl/writel
|
||||
*
|
||||
* 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
* - Make use of some undocumented features of the touchscreen
|
||||
* controller
|
||||
*
|
||||
* 2007-05-23: Harald Welte <laforge@openmoko.org>
|
||||
* - Add proper support for S32440
|
||||
*
|
||||
* 2008-06-23: Andy Green <andy@openmoko.com>
|
||||
* - removed averaging system
|
||||
* - added generic Touchscreen filter stuff
|
||||
*
|
||||
* 2008-11-27: Nelson Castillo <arhuaco@freaks-unidos.net>
|
||||
* - improve interrupt handling
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/ts.h>
|
||||
#include <mach/gpio-fns.h>
|
||||
#include <plat/regs-adc.h>
|
||||
|
||||
#include <linux/touchscreen/ts_filter_chain.h>
|
||||
|
||||
/* For ts.dev.id.version */
|
||||
#define S3C2410TSVERSION 0x0101
|
||||
|
||||
#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
|
||||
|
||||
#define WAIT4INT(x) (((x)<<8) | \
|
||||
S3C2410_ADCTSC_YM_SEN | \
|
||||
S3C2410_ADCTSC_YP_SEN | \
|
||||
S3C2410_ADCTSC_XP_SEN | \
|
||||
S3C2410_ADCTSC_XY_PST(3))
|
||||
|
||||
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \
|
||||
S3C2410_ADCTSC_YP_SEN | \
|
||||
S3C2410_ADCTSC_XP_SEN | \
|
||||
S3C2410_ADCTSC_AUTO_PST | \
|
||||
S3C2410_ADCTSC_XY_PST(0))
|
||||
|
||||
#define DEBUG_LVL KERN_DEBUG
|
||||
|
||||
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
|
||||
MODULE_DESCRIPTION("s3c2410 touchscreen driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
static char *s3c2410ts_name = "s3c2410 TouchScreen";
|
||||
|
||||
#define TS_RELEASE_TIMEOUT (HZ >> 7 ? HZ >> 7 : 1) /* 8ms (5ms if HZ is 200) */
|
||||
#define TS_EVENT_FIFO_SIZE (2 << 6) /* must be a power of 2 */
|
||||
|
||||
#define TS_STATE_STANDBY 0 /* initial state */
|
||||
#define TS_STATE_PRESSED 1
|
||||
#define TS_STATE_RELEASE_PENDING 2
|
||||
#define TS_STATE_RELEASE 3
|
||||
|
||||
/*
|
||||
* Per-touchscreen data.
|
||||
*/
|
||||
|
||||
struct s3c2410ts {
|
||||
struct input_dev *dev;
|
||||
struct ts_filter_chain *chain;
|
||||
int is_down;
|
||||
int state;
|
||||
struct kfifo *event_fifo;
|
||||
};
|
||||
|
||||
static struct s3c2410ts ts;
|
||||
|
||||
static void __iomem *base_addr;
|
||||
|
||||
/*
|
||||
* A few low level functions.
|
||||
*/
|
||||
|
||||
static inline void s3c2410_ts_connect(void)
|
||||
{
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
|
||||
s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
|
||||
}
|
||||
|
||||
static void s3c2410_ts_start_adc_conversion(void)
|
||||
{
|
||||
writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
|
||||
base_addr + S3C2410_ADCTSC);
|
||||
writel(readl(base_addr + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,
|
||||
base_addr + S3C2410_ADCCON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just send the input events.
|
||||
*/
|
||||
|
||||
enum ts_input_event {IE_DOWN = 0, IE_UP};
|
||||
|
||||
static void ts_input_report(int event, int coords[])
|
||||
{
|
||||
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
|
||||
static char *s[] = {"down", "up"};
|
||||
struct timeval tv;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
#endif
|
||||
|
||||
if (event == IE_DOWN) {
|
||||
input_report_abs(ts.dev, ABS_X, coords[0]);
|
||||
input_report_abs(ts.dev, ABS_Y, coords[1]);
|
||||
input_report_key(ts.dev, BTN_TOUCH, 1);
|
||||
input_report_abs(ts.dev, ABS_PRESSURE, 1);
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
|
||||
printk(DEBUG_LVL "T:%06d %6s (X:%03d, Y:%03d)\n",
|
||||
(int)tv.tv_usec, s[event], coords[0], coords[1]);
|
||||
#endif
|
||||
} else {
|
||||
input_report_key(ts.dev, BTN_TOUCH, 0);
|
||||
input_report_abs(ts.dev, ABS_PRESSURE, 0);
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
|
||||
printk(DEBUG_LVL "T:%06d %6s\n",
|
||||
(int)tv.tv_usec, s[event]);
|
||||
#endif
|
||||
}
|
||||
|
||||
input_sync(ts.dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manage the state of the touchscreen.
|
||||
*/
|
||||
|
||||
static void event_send_timer_f(unsigned long data);
|
||||
|
||||
static struct timer_list event_send_timer =
|
||||
TIMER_INITIALIZER(event_send_timer_f, 0, 0);
|
||||
|
||||
static void event_send_timer_f(unsigned long data)
|
||||
{
|
||||
static int noop_counter;
|
||||
int event_type;
|
||||
|
||||
while (__kfifo_get(ts.event_fifo, (unsigned char *)&event_type,
|
||||
sizeof(int))) {
|
||||
int buf[2];
|
||||
|
||||
switch (event_type) {
|
||||
case 'D':
|
||||
if (ts.state == TS_STATE_RELEASE_PENDING)
|
||||
/* Ignore short UP event */
|
||||
ts.state = TS_STATE_PRESSED;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
ts.state = TS_STATE_RELEASE_PENDING;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
if (ts.is_down) /* stylus_action needs a conversion */
|
||||
s3c2410_ts_start_adc_conversion();
|
||||
|
||||
if (unlikely(__kfifo_get(ts.event_fifo,
|
||||
(unsigned char *)buf,
|
||||
sizeof(int) * 2)
|
||||
!= sizeof(int) * 2))
|
||||
goto ts_exit_error;
|
||||
|
||||
ts_input_report(IE_DOWN, buf);
|
||||
ts.state = TS_STATE_PRESSED;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto ts_exit_error;
|
||||
}
|
||||
|
||||
noop_counter = 0;
|
||||
}
|
||||
|
||||
if (noop_counter++ >= 1) {
|
||||
noop_counter = 0;
|
||||
if (ts.state == TS_STATE_RELEASE_PENDING) {
|
||||
/*
|
||||
* We delay the UP event for a while to avoid jitter.
|
||||
* If we get a DOWN event we do not send it.
|
||||
*/
|
||||
ts_input_report(IE_UP, NULL);
|
||||
ts.state = TS_STATE_STANDBY;
|
||||
|
||||
ts_filter_chain_clear(ts.chain);
|
||||
}
|
||||
} else {
|
||||
mod_timer(&event_send_timer, jiffies + TS_RELEASE_TIMEOUT);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
ts_exit_error: /* should not happen unless we have a bug */
|
||||
printk(KERN_ERR __FILE__ ": event_send_timer_f failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Manage interrupts.
|
||||
*/
|
||||
|
||||
static irqreturn_t stylus_updown(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long data0;
|
||||
unsigned long data1;
|
||||
int event_type;
|
||||
|
||||
data0 = readl(base_addr+S3C2410_ADCDAT0);
|
||||
data1 = readl(base_addr+S3C2410_ADCDAT1);
|
||||
|
||||
ts.is_down = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
|
||||
(!(data1 & S3C2410_ADCDAT0_UPDOWN));
|
||||
|
||||
event_type = ts.is_down ? 'D' : 'U';
|
||||
|
||||
if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)&event_type,
|
||||
sizeof(int)) != sizeof(int))) /* should not happen */
|
||||
printk(KERN_ERR __FILE__": stylus_updown lost event!\n");
|
||||
|
||||
if (ts.is_down)
|
||||
s3c2410_ts_start_adc_conversion();
|
||||
else
|
||||
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
|
||||
|
||||
mod_timer(&event_send_timer, jiffies + 1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t stylus_action(int irq, void *dev_id)
|
||||
{
|
||||
int buf[3];
|
||||
|
||||
/* Grab the ADC results. */
|
||||
buf[1] = readl(base_addr + S3C2410_ADCDAT0) &
|
||||
S3C2410_ADCDAT0_XPDATA_MASK;
|
||||
buf[2] = readl(base_addr + S3C2410_ADCDAT1) &
|
||||
S3C2410_ADCDAT1_YPDATA_MASK;
|
||||
|
||||
switch (ts_filter_chain_feed(ts.chain, &buf[1])) {
|
||||
case 0:
|
||||
/* The filter wants more points. */
|
||||
s3c2410_ts_start_adc_conversion();
|
||||
return IRQ_HANDLED;
|
||||
case 1:
|
||||
/* We have a point from the filters or no filtering enabled. */
|
||||
buf[0] = 'P';
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR __FILE__
|
||||
":%d Invalid ts_filter_chain_feed return value.\n",
|
||||
__LINE__);
|
||||
case -1:
|
||||
/* Error. Ignore the event. */
|
||||
ts_filter_chain_clear(ts.chain);
|
||||
writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
|
||||
return IRQ_HANDLED;
|
||||
};
|
||||
|
||||
if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)buf,
|
||||
sizeof(int) * 3) != sizeof(int) * 3))
|
||||
printk(KERN_ERR __FILE__":stylus_action bug.\n");
|
||||
|
||||
writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
|
||||
mod_timer(&event_send_timer, jiffies + 1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct clk *adc_clock;
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
static int __init s3c2410ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
struct s3c2410_ts_mach_info *info;
|
||||
struct input_dev *input_dev;
|
||||
int ret = 0;
|
||||
|
||||
dev_info(&pdev->dev, "Starting\n");
|
||||
|
||||
info = (struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
|
||||
|
||||
if (!info)
|
||||
{
|
||||
dev_err(&pdev->dev, "Hm... too bad: no platform data for ts\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
|
||||
printk(DEBUG_LVL "Entering s3c2410ts_init\n");
|
||||
#endif
|
||||
|
||||
adc_clock = clk_get(NULL, "adc");
|
||||
if (!adc_clock) {
|
||||
dev_err(&pdev->dev, "failed to get adc clock source\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
clk_enable(adc_clock);
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
|
||||
printk(DEBUG_LVL "got and enabled clock\n");
|
||||
#endif
|
||||
|
||||
base_addr = ioremap(S3C2410_PA_ADC,0x20);
|
||||
if (base_addr == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to remap register block\n");
|
||||
ret = -ENOMEM;
|
||||
goto bail0;
|
||||
}
|
||||
|
||||
|
||||
/* If we acutally are a S3C2410: Configure GPIOs */
|
||||
if (!strcmp(pdev->name, "s3c2410-ts"))
|
||||
s3c2410_ts_connect();
|
||||
|
||||
if ((info->presc & 0xff) > 0)
|
||||
writel(S3C2410_ADCCON_PRSCEN |
|
||||
S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
|
||||
base_addr + S3C2410_ADCCON);
|
||||
else
|
||||
writel(0, base_addr+S3C2410_ADCCON);
|
||||
|
||||
/* Initialise registers */
|
||||
if ((info->delay & 0xffff) > 0)
|
||||
writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);
|
||||
|
||||
writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);
|
||||
|
||||
/* Initialise input stuff */
|
||||
memset(&ts, 0, sizeof(struct s3c2410ts));
|
||||
input_dev = input_allocate_device();
|
||||
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "Unable to allocate the input device\n");
|
||||
ret = -ENOMEM;
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
ts.dev = input_dev;
|
||||
ts.dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |
|
||||
BIT_MASK(EV_ABS);
|
||||
ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
|
||||
input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
|
||||
input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
|
||||
|
||||
ts.dev->name = s3c2410ts_name;
|
||||
ts.dev->id.bustype = BUS_RS232;
|
||||
ts.dev->id.vendor = 0xDEAD;
|
||||
ts.dev->id.product = 0xBEEF;
|
||||
ts.dev->id.version = S3C2410TSVERSION;
|
||||
ts.state = TS_STATE_STANDBY;
|
||||
ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);
|
||||
if (IS_ERR(ts.event_fifo)) {
|
||||
ret = -EIO;
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* create the filter chain set up for the 2 coordinates we produce */
|
||||
ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);
|
||||
|
||||
if (IS_ERR(ts.chain))
|
||||
goto bail2;
|
||||
|
||||
ts_filter_chain_clear(ts.chain);
|
||||
|
||||
/* Get irqs */
|
||||
if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
|
||||
"s3c2410_action", ts.dev)) {
|
||||
dev_err(&pdev->dev, "Could not allocate ts IRQ_ADC !\n");
|
||||
iounmap(base_addr);
|
||||
ret = -EIO;
|
||||
goto bail3;
|
||||
}
|
||||
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
|
||||
"s3c2410_action", ts.dev)) {
|
||||
dev_err(&pdev->dev, "Could not allocate ts IRQ_TC !\n");
|
||||
free_irq(IRQ_ADC, ts.dev);
|
||||
iounmap(base_addr);
|
||||
ret = -EIO;
|
||||
goto bail4;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Successfully loaded\n");
|
||||
|
||||
/* All went ok, so register to the input system */
|
||||
rc = input_register_device(ts.dev);
|
||||
if (rc) {
|
||||
ret = -EIO;
|
||||
goto bail5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail5:
|
||||
free_irq(IRQ_TC, ts.dev);
|
||||
free_irq(IRQ_ADC, ts.dev);
|
||||
clk_disable(adc_clock);
|
||||
iounmap(base_addr);
|
||||
disable_irq(IRQ_TC);
|
||||
bail4:
|
||||
disable_irq(IRQ_ADC);
|
||||
bail3:
|
||||
ts_filter_chain_destroy(ts.chain);
|
||||
kfifo_free(ts.event_fifo);
|
||||
bail2:
|
||||
input_unregister_device(ts.dev);
|
||||
bail1:
|
||||
iounmap(base_addr);
|
||||
bail0:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c2410ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
disable_irq(IRQ_ADC);
|
||||
disable_irq(IRQ_TC);
|
||||
free_irq(IRQ_TC,ts.dev);
|
||||
free_irq(IRQ_ADC,ts.dev);
|
||||
|
||||
if (adc_clock) {
|
||||
clk_disable(adc_clock);
|
||||
clk_put(adc_clock);
|
||||
adc_clock = NULL;
|
||||
}
|
||||
|
||||
input_unregister_device(ts.dev);
|
||||
iounmap(base_addr);
|
||||
|
||||
ts_filter_chain_destroy(ts.chain);
|
||||
|
||||
kfifo_free(ts.event_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s3c2410ts_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
writel(TSC_SLEEP, base_addr+S3C2410_ADCTSC);
|
||||
writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_STDBM,
|
||||
base_addr+S3C2410_ADCCON);
|
||||
|
||||
disable_irq(IRQ_ADC);
|
||||
disable_irq(IRQ_TC);
|
||||
|
||||
clk_disable(adc_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2410ts_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c2410_ts_mach_info *info =
|
||||
( struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
|
||||
|
||||
clk_enable(adc_clock);
|
||||
mdelay(1);
|
||||
|
||||
ts_filter_chain_clear(ts.chain);
|
||||
|
||||
enable_irq(IRQ_ADC);
|
||||
enable_irq(IRQ_TC);
|
||||
|
||||
if ((info->presc&0xff) > 0)
|
||||
writel(S3C2410_ADCCON_PRSCEN |
|
||||
S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
|
||||
base_addr+S3C2410_ADCCON);
|
||||
else
|
||||
writel(0,base_addr+S3C2410_ADCCON);
|
||||
|
||||
/* Initialise registers */
|
||||
if ((info->delay & 0xffff) > 0)
|
||||
writel(info->delay & 0xffff, base_addr+S3C2410_ADCDLY);
|
||||
|
||||
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define s3c2410ts_suspend NULL
|
||||
#define s3c2410ts_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver s3c2410ts_driver = {
|
||||
.driver = {
|
||||
.name = "s3c2410-ts",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s3c2410ts_probe,
|
||||
.remove = s3c2410ts_remove,
|
||||
.suspend = s3c2410ts_suspend,
|
||||
.resume = s3c2410ts_resume,
|
||||
|
||||
};
|
||||
|
||||
static struct platform_driver s3c2440ts_driver = {
|
||||
.driver = {
|
||||
.name = "s3c2440-ts",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s3c2410ts_probe,
|
||||
.remove = s3c2410ts_remove,
|
||||
.suspend = s3c2410ts_suspend,
|
||||
.resume = s3c2410ts_resume,
|
||||
|
||||
};
|
||||
|
||||
static int __init s3c2410ts_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = platform_driver_register(&s3c2410ts_driver);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = platform_driver_register(&s3c2440ts_driver);
|
||||
if (rc < 0)
|
||||
platform_driver_unregister(&s3c2410ts_driver);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit s3c2410ts_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&s3c2440ts_driver);
|
||||
platform_driver_unregister(&s3c2410ts_driver);
|
||||
}
|
||||
|
||||
module_init(s3c2410ts_init);
|
||||
module_exit(s3c2410ts_exit);
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2008,2009 Andy Green <andy@openmoko.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <linux/touchscreen/ts_filter_chain.h>
|
||||
#include <linux/touchscreen/ts_filter.h>
|
||||
|
||||
/*
|
||||
* Tux, would you like the following function in /lib?
|
||||
* It helps us avoid silly code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* sptrlen - Count how many non-null pointers are in a pointer array
|
||||
* @arr: The array of pointers
|
||||
*/
|
||||
static int sptrlen(const void *arr)
|
||||
{
|
||||
/* All pointers have the same size. */
|
||||
const int **p = (const int **)arr;
|
||||
int len = 0;
|
||||
|
||||
while (*(p++))
|
||||
len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
struct ts_filter_chain {
|
||||
/* All of the filters. */
|
||||
struct ts_filter **arr;
|
||||
/* Filters that can propagate values in the chain. */
|
||||
struct ts_filter **pchain;
|
||||
/* Length of the pchain array. */
|
||||
int pchain_len;
|
||||
/* FIXME: Add a spinlock and use it. */
|
||||
};
|
||||
|
||||
struct ts_filter_chain *ts_filter_chain_create(
|
||||
struct platform_device *pdev,
|
||||
const struct ts_filter_chain_configuration conf[],
|
||||
int count_coords)
|
||||
{
|
||||
struct ts_filter_chain *c;
|
||||
int count = 0;
|
||||
int len;
|
||||
|
||||
BUG_ON((count_coords < 1));
|
||||
BUG_ON(count_coords > MAX_TS_FILTER_COORDS);
|
||||
|
||||
c = kzalloc(sizeof(struct ts_filter_chain), GFP_KERNEL);
|
||||
if (!c)
|
||||
goto create_err_1;
|
||||
|
||||
len = (sptrlen(conf) + 1);
|
||||
/* Memory for two null-terminated arrays of filters. */
|
||||
c->arr = kzalloc(2 * sizeof(struct ts_filter *) * len, GFP_KERNEL);
|
||||
if (!c->arr)
|
||||
goto create_err_1;
|
||||
c->pchain = c->arr + len;
|
||||
|
||||
while (conf->api) {
|
||||
/* TODO: Can we get away with only sending pdev->dev? */
|
||||
struct ts_filter *f =
|
||||
(conf->api->create)(pdev, conf->config, count_coords);
|
||||
if (!f) {
|
||||
dev_info(&pdev->dev, "Filter %d creation failed\n",
|
||||
count);
|
||||
goto create_err_2;
|
||||
}
|
||||
|
||||
f->api = conf->api;
|
||||
c->arr[count++] = f;
|
||||
|
||||
if (f->api->haspoint && f->api->getpoint && f->api->process)
|
||||
c->pchain[c->pchain_len++] = f;
|
||||
|
||||
conf++;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%d filter(s) initialized\n", count);
|
||||
|
||||
return c;
|
||||
|
||||
create_err_2:
|
||||
ts_filter_chain_destroy(c); /* Also frees c. */
|
||||
create_err_1:
|
||||
dev_info(&pdev->dev, "Error in filter chain initialization\n");
|
||||
/*
|
||||
* FIXME: Individual filters have to return errors this way.
|
||||
* We only have to forward the errors we find.
|
||||
*/
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ts_filter_chain_create);
|
||||
|
||||
void ts_filter_chain_destroy(struct ts_filter_chain *c)
|
||||
{
|
||||
if (c->arr) {
|
||||
struct ts_filter **a = c->arr;
|
||||
while (*a) {
|
||||
((*a)->api->destroy)(*a);
|
||||
a++;
|
||||
}
|
||||
kfree(c->arr);
|
||||
}
|
||||
kfree(c);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ts_filter_chain_destroy);
|
||||
|
||||
void ts_filter_chain_clear(struct ts_filter_chain *c)
|
||||
{
|
||||
struct ts_filter **a = c->arr;
|
||||
|
||||
while (*a) {
|
||||
if ((*a)->api->clear)
|
||||
((*a)->api->clear)(*a);
|
||||
a++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ts_filter_chain_clear);
|
||||
|
||||
static void ts_filter_chain_scale(struct ts_filter_chain *c, int *coords)
|
||||
{
|
||||
struct ts_filter **a = c->arr;
|
||||
while (*a) {
|
||||
if ((*a)->api->scale)
|
||||
((*a)->api->scale)(*a, coords);
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
int ts_filter_chain_feed(struct ts_filter_chain *c, int *coords)
|
||||
{
|
||||
int len = c->pchain_len;
|
||||
int i = len - 1;
|
||||
|
||||
if (!c->pchain[0])
|
||||
return 1; /* Nothing to do. */
|
||||
|
||||
BUG_ON(c->pchain[0]->api->haspoint(c->pchain[0]));
|
||||
|
||||
if (c->pchain[0]->api->process(c->pchain[0], coords))
|
||||
return -1;
|
||||
|
||||
while (i >= 0 && i < len) {
|
||||
if (c->pchain[i]->api->haspoint(c->pchain[i])) {
|
||||
c->pchain[i]->api->getpoint(c->pchain[i], coords);
|
||||
if (++i < len &&
|
||||
c->pchain[i]->api->process(c->pchain[i], coords))
|
||||
return -1; /* Error. */
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= 0) { /* Same as i == len. */
|
||||
ts_filter_chain_scale(c, coords);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ts_filter_chain_feed);
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (C) 2008,2009 by Openmoko, Inc.
|
||||
* Author: Nelson Castillo <arhuaco@freaks-unidos.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* This filter is useful to reject samples that are not reliable. We consider
|
||||
* that a sample is not reliable if it deviates form the Majority.
|
||||
*
|
||||
* 1) We collect S samples.
|
||||
*
|
||||
* 2) For each dimension:
|
||||
*
|
||||
* - We sort the points.
|
||||
* - Points that are "close enough" are considered to be in the same set.
|
||||
* - We choose the set with more elements. If more than "threshold"
|
||||
* points are in this set we use the first and the last point of the set
|
||||
* to define the valid range for this dimension [min, max], otherwise we
|
||||
* discard all the points and go to step 1.
|
||||
*
|
||||
* 3) We consider the unsorted S samples and try to feed them to the next
|
||||
* filter in the chain. If one of the points of each sample
|
||||
* is not in the allowed range for its dimension, we discard the sample.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/touchscreen/ts_filter_group.h>
|
||||
|
||||
struct ts_filter_group {
|
||||
/* Private filter configuration. */
|
||||
struct ts_filter_group_configuration *config;
|
||||
/* Filter API. */
|
||||
struct ts_filter tsf;
|
||||
|
||||
int N; /* How many samples we have. */
|
||||
int *samples[MAX_TS_FILTER_COORDS]; /* The samples: our input. */
|
||||
|
||||
int *group_size; /* Used for temporal computations. */
|
||||
int *sorted_samples; /* Used for temporal computations. */
|
||||
|
||||
int range_max[MAX_TS_FILTER_COORDS]; /* Max. computed ranges. */
|
||||
int range_min[MAX_TS_FILTER_COORDS]; /* Min. computed ranges. */
|
||||
|
||||
int tries_left; /* We finish if we don't get enough samples. */
|
||||
int ready; /* If we are ready to deliver samples. */
|
||||
int result; /* Index of the point being returned. */
|
||||
};
|
||||
|
||||
#define ts_filter_to_filter_group(f) \
|
||||
container_of(f, struct ts_filter_group, tsf)
|
||||
|
||||
|
||||
static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg,
|
||||
int attempts)
|
||||
{
|
||||
tsfg->N = 0;
|
||||
tsfg->tries_left = attempts;
|
||||
tsfg->ready = 0;
|
||||
tsfg->result = 0;
|
||||
}
|
||||
|
||||
static void ts_filter_group_clear(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
|
||||
|
||||
ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
|
||||
}
|
||||
|
||||
static struct ts_filter *ts_filter_group_create(
|
||||
struct platform_device *pdev,
|
||||
const struct ts_filter_configuration *conf,
|
||||
int count_coords)
|
||||
{
|
||||
struct ts_filter_group *tsfg;
|
||||
int i;
|
||||
|
||||
tsfg = kzalloc(sizeof(struct ts_filter_group), GFP_KERNEL);
|
||||
if (!tsfg)
|
||||
return NULL;
|
||||
|
||||
tsfg->config = container_of(conf,
|
||||
struct ts_filter_group_configuration,
|
||||
config);
|
||||
tsfg->tsf.count_coords = count_coords;
|
||||
|
||||
BUG_ON(tsfg->config->attempts <= 0);
|
||||
|
||||
tsfg->samples[0] = kmalloc((2 + count_coords) * sizeof(int) *
|
||||
tsfg->config->length, GFP_KERNEL);
|
||||
if (!tsfg->samples[0]) {
|
||||
kfree(tsfg);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 1; i < count_coords; ++i)
|
||||
tsfg->samples[i] = tsfg->samples[0] + i * tsfg->config->length;
|
||||
tsfg->sorted_samples = tsfg->samples[0] + count_coords *
|
||||
tsfg->config->length;
|
||||
tsfg->group_size = tsfg->samples[0] + (1 + count_coords) *
|
||||
tsfg->config->length;
|
||||
|
||||
ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
|
||||
|
||||
dev_info(&pdev->dev, "Created Group filter len:%d coords:%d close:%d "
|
||||
"thresh:%d\n", tsfg->config->length, count_coords,
|
||||
tsfg->config->close_enough, tsfg->config->threshold);
|
||||
|
||||
return &tsfg->tsf;
|
||||
}
|
||||
|
||||
static void ts_filter_group_destroy(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
|
||||
|
||||
kfree(tsfg->samples[0]); /* first guy has pointer from kmalloc */
|
||||
kfree(tsf);
|
||||
}
|
||||
|
||||
static int int_cmp(const void *_a, const void *_b)
|
||||
{
|
||||
const int *a = _a;
|
||||
const int *b = _b;
|
||||
|
||||
if (*a > *b)
|
||||
return 1;
|
||||
if (*a < *b)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ts_filter_group_prepare_next(struct ts_filter *tsf);
|
||||
|
||||
static int ts_filter_group_process(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
|
||||
int n;
|
||||
int i;
|
||||
|
||||
BUG_ON(tsfg->N >= tsfg->config->length);
|
||||
BUG_ON(tsfg->ready);
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++)
|
||||
tsfg->samples[n][tsfg->N] = coords[n];
|
||||
|
||||
if (++tsfg->N < tsfg->config->length)
|
||||
return 0; /* We need more samples. */
|
||||
|
||||
for (n = 0; n < tsfg->tsf.count_coords; n++) {
|
||||
int *v = tsfg->sorted_samples;
|
||||
int ngroups = 0;
|
||||
int best_size;
|
||||
int best_idx = 0;
|
||||
int idx = 0;
|
||||
|
||||
memcpy(v, tsfg->samples[n], tsfg->N * sizeof(int));
|
||||
/*
|
||||
* FIXME: Remove this sort call. We already have the
|
||||
* algorithm for this modification. The filter will
|
||||
* need less points (about half) if there is not a
|
||||
* lot of noise. Right now we are doing a constant
|
||||
* amount of work no matter how much noise we are
|
||||
* dealing with.
|
||||
*/
|
||||
sort(v, tsfg->N, sizeof(int), int_cmp, NULL);
|
||||
|
||||
tsfg->group_size[0] = 1;
|
||||
for (i = 1; i < tsfg->N; ++i) {
|
||||
if (v[i] - v[i - 1] <= tsfg->config->close_enough)
|
||||
tsfg->group_size[ngroups]++;
|
||||
else
|
||||
tsfg->group_size[++ngroups] = 1;
|
||||
}
|
||||
ngroups++;
|
||||
|
||||
best_size = tsfg->group_size[0];
|
||||
for (i = 1; i < ngroups; i++) {
|
||||
idx += tsfg->group_size[i - 1];
|
||||
if (best_size < tsfg->group_size[i]) {
|
||||
best_size = tsfg->group_size[i];
|
||||
best_idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_size < tsfg->config->threshold) {
|
||||
/* This set is not good enough for us. */
|
||||
if (--tsfg->tries_left) {
|
||||
ts_filter_group_clear_internal
|
||||
(tsfg, tsfg->tries_left);
|
||||
/* No errors but we need more samples. */
|
||||
return 0;
|
||||
}
|
||||
return 1; /* We give up: error. */
|
||||
}
|
||||
|
||||
tsfg->range_min[n] = v[best_idx];
|
||||
tsfg->range_max[n] = v[best_idx + best_size - 1];
|
||||
}
|
||||
|
||||
ts_filter_group_prepare_next(tsf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This private function prepares a point that will be returned
|
||||
* in ts_filter_group_getpoint if it is available. It updates
|
||||
* the priv->ready state also.
|
||||
*/
|
||||
static void ts_filter_group_prepare_next(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
|
||||
int n;
|
||||
|
||||
while (priv->result < priv->N) {
|
||||
for (n = 0; n < priv->tsf.count_coords; ++n) {
|
||||
if (priv->samples[n][priv->result] <
|
||||
priv->range_min[n] ||
|
||||
priv->samples[n][priv->result] > priv->range_max[n])
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == priv->tsf.count_coords) /* Sample is OK. */
|
||||
break;
|
||||
|
||||
priv->result++;
|
||||
}
|
||||
|
||||
if (unlikely(priv->result >= priv->N)) { /* No sample to deliver. */
|
||||
ts_filter_group_clear_internal(priv, priv->config->attempts);
|
||||
priv->ready = 0;
|
||||
} else {
|
||||
priv->ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int ts_filter_group_haspoint(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
|
||||
|
||||
return priv->ready;
|
||||
}
|
||||
|
||||
static void ts_filter_group_getpoint(struct ts_filter *tsf, int *point)
|
||||
{
|
||||
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
|
||||
int n;
|
||||
|
||||
BUG_ON(!priv->ready);
|
||||
|
||||
for (n = 0; n < priv->tsf.count_coords; n++)
|
||||
point[n] = priv->samples[n][priv->result];
|
||||
|
||||
priv->result++;
|
||||
|
||||
/* This call will update priv->ready. */
|
||||
ts_filter_group_prepare_next(tsf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get ready to process the next batch of points, forget
|
||||
* points we could have delivered.
|
||||
*/
|
||||
static void ts_filter_group_scale(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
|
||||
|
||||
ts_filter_group_clear_internal(priv, priv->config->attempts);
|
||||
}
|
||||
|
||||
const struct ts_filter_api ts_filter_group_api = {
|
||||
.create = ts_filter_group_create,
|
||||
.destroy = ts_filter_group_destroy,
|
||||
.clear = ts_filter_group_clear,
|
||||
.process = ts_filter_group_process,
|
||||
.haspoint = ts_filter_group_haspoint,
|
||||
.getpoint = ts_filter_group_getpoint,
|
||||
.scale = ts_filter_group_scale,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ts_filter_group_api);
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 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
|
||||
*
|
||||
* Copyright (C) 2008,2009 by Openmoko, Inc.
|
||||
* Author: Nelson Castillo <arhuaco@freaks-unidos.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Linearly scale touchscreen values.
|
||||
*
|
||||
* Expose the TS_FILTER_LINEAR_NCONSTANTS for the linear transformation
|
||||
* using sysfs.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/touchscreen/ts_filter_linear.h>
|
||||
|
||||
struct ts_filter_linear;
|
||||
|
||||
/* Sysfs code. */
|
||||
|
||||
struct const_obj {
|
||||
/* The actual private object. */
|
||||
struct ts_filter_linear *tsfl;
|
||||
/* Our kobject. */
|
||||
struct kobject kobj;
|
||||
};
|
||||
|
||||
#define to_const_obj(x) container_of(x, struct const_obj, kobj)
|
||||
|
||||
struct const_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct const_obj *const, struct const_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct const_obj *const, struct const_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
#define to_const_attr(x) container_of(x, struct const_attribute, attr)
|
||||
|
||||
|
||||
/* Private linear filter structure. */
|
||||
|
||||
struct ts_filter_linear {
|
||||
/* Private configuration for this filter. */
|
||||
struct ts_filter_linear_configuration *config;
|
||||
|
||||
/* Generic filter API. */
|
||||
struct ts_filter tsf;
|
||||
|
||||
/* Linear constants for the transformation. */
|
||||
int constants[TS_FILTER_LINEAR_NCONSTANTS];
|
||||
|
||||
/* Sysfs. */
|
||||
|
||||
/* Our const_object. */
|
||||
struct const_obj c_obj;
|
||||
/* Our type. We will stick operations to it. */
|
||||
struct kobj_type const_ktype;
|
||||
/* Attrs. of the virtual files. */
|
||||
struct const_attribute kattrs[TS_FILTER_LINEAR_NCONSTANTS];
|
||||
/* Default Attrs. Always NULL for us. */
|
||||
struct attribute *attrs[TS_FILTER_LINEAR_NCONSTANTS + 1];
|
||||
/* Storage for the name of the virtual files. */
|
||||
char attr_names[TS_FILTER_LINEAR_NCONSTANTS][2];
|
||||
};
|
||||
|
||||
#define ts_filter_to_filter_linear(f) \
|
||||
container_of(f, struct ts_filter_linear, tsf)
|
||||
|
||||
/* Sysfs functions. */
|
||||
|
||||
static ssize_t const_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct const_attribute *a = to_const_attr(attr);
|
||||
|
||||
return a->show(to_const_obj(kobj), a, buf);
|
||||
}
|
||||
|
||||
static ssize_t const_attr_store(struct kobject *kobj,
|
||||
struct attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct const_attribute *a = to_const_attr(attr);
|
||||
|
||||
return a->store(to_const_obj(kobj), a, buf, len);
|
||||
}
|
||||
|
||||
static struct sysfs_ops const_sysfs_ops = {
|
||||
.show = const_attr_show,
|
||||
.store = const_attr_store,
|
||||
};
|
||||
|
||||
static void const_release(struct kobject *kobj)
|
||||
{
|
||||
kfree(to_const_obj(kobj)->tsfl);
|
||||
}
|
||||
|
||||
static ssize_t const_show(struct const_obj *obj, struct const_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int who;
|
||||
|
||||
sscanf(attr->attr.name, "%d", &who);
|
||||
return sprintf(buf, "%d\n", obj->tsfl->constants[who]);
|
||||
}
|
||||
|
||||
static ssize_t const_store(struct const_obj *obj, struct const_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int who;
|
||||
|
||||
sscanf(attr->attr.name, "%d", &who);
|
||||
sscanf(buf, "%d", &obj->tsfl->constants[who]);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Filter functions. */
|
||||
|
||||
static struct ts_filter *ts_filter_linear_create(
|
||||
struct platform_device *pdev,
|
||||
const struct ts_filter_configuration *conf,
|
||||
int count_coords)
|
||||
{
|
||||
struct ts_filter_linear *tsfl;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
tsfl = kzalloc(sizeof(struct ts_filter_linear), GFP_KERNEL);
|
||||
if (!tsfl)
|
||||
return NULL;
|
||||
|
||||
tsfl->config = container_of(conf,
|
||||
struct ts_filter_linear_configuration,
|
||||
config);
|
||||
|
||||
tsfl->tsf.count_coords = count_coords;
|
||||
|
||||
for (i = 0; i < TS_FILTER_LINEAR_NCONSTANTS; ++i) {
|
||||
tsfl->constants[i] = tsfl->config->constants[i];
|
||||
|
||||
/* sysfs */
|
||||
sprintf(tsfl->attr_names[i], "%d", i);
|
||||
tsfl->kattrs[i].attr.name = tsfl->attr_names[i];
|
||||
tsfl->kattrs[i].attr.mode = 0666;
|
||||
tsfl->kattrs[i].show = const_show;
|
||||
tsfl->kattrs[i].store = const_store;
|
||||
tsfl->attrs[i] = &tsfl->kattrs[i].attr;
|
||||
}
|
||||
tsfl->attrs[i] = NULL;
|
||||
|
||||
tsfl->const_ktype.sysfs_ops = &const_sysfs_ops;
|
||||
tsfl->const_ktype.release = const_release;
|
||||
tsfl->const_ktype.default_attrs = tsfl->attrs;
|
||||
tsfl->c_obj.tsfl = tsfl; /* kernel frees tsfl in const_release */
|
||||
|
||||
ret = kobject_init_and_add(&tsfl->c_obj.kobj, &tsfl->const_ktype,
|
||||
&pdev->dev.kobj, "calibration");
|
||||
if (ret) {
|
||||
kobject_put(&tsfl->c_obj.kobj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Created Linear filter coords:%d\n", count_coords);
|
||||
|
||||
return &tsfl->tsf;
|
||||
}
|
||||
|
||||
static void ts_filter_linear_destroy(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
|
||||
|
||||
/* Kernel frees tsfl in const_release. */
|
||||
kobject_put(&tsfl->c_obj.kobj);
|
||||
}
|
||||
|
||||
static void ts_filter_linear_scale(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
|
||||
|
||||
int *k = tsfl->constants;
|
||||
int c0 = coords[tsfl->config->coord0];
|
||||
int c1 = coords[tsfl->config->coord1];
|
||||
|
||||
coords[tsfl->config->coord0] = (k[2] + k[0] * c0 + k[1] * c1) / k[6];
|
||||
coords[tsfl->config->coord1] = (k[5] + k[3] * c0 + k[4] * c1) / k[6];
|
||||
}
|
||||
|
||||
const struct ts_filter_api ts_filter_linear_api = {
|
||||
.create = ts_filter_linear_create,
|
||||
.destroy = ts_filter_linear_destroy,
|
||||
.scale = ts_filter_linear_scale,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ts_filter_linear_api);
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2008,2009
|
||||
* Andy Green <andy@openmoko.com>
|
||||
* Nelson Castillo <arhuaco@freaks-unidos.net>
|
||||
*
|
||||
* Simple mean filter.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/touchscreen/ts_filter_mean.h>
|
||||
|
||||
struct ts_filter_mean {
|
||||
/* Copy of the private filter configuration. */
|
||||
struct ts_filter_mean_configuration *config;
|
||||
/* Filter API. */
|
||||
struct ts_filter tsf;
|
||||
|
||||
/* Index on a circular buffer. */
|
||||
int curr;
|
||||
/* Useful to tell if the circular buffer is full(read:ready). */
|
||||
int count;
|
||||
/* Sumation used to compute the mean. */
|
||||
int sum[MAX_TS_FILTER_COORDS];
|
||||
/* Keep point values and decrement them from the sum on time. */
|
||||
int *fifo[MAX_TS_FILTER_COORDS];
|
||||
/* Store the output of this filter. */
|
||||
int ready;
|
||||
};
|
||||
|
||||
#define ts_filter_to_filter_mean(f) container_of(f, struct ts_filter_mean, tsf)
|
||||
|
||||
|
||||
static void ts_filter_mean_clear(struct ts_filter *tsf);
|
||||
|
||||
static struct ts_filter *ts_filter_mean_create(
|
||||
struct platform_device *pdev,
|
||||
const struct ts_filter_configuration *conf,
|
||||
int count_coords)
|
||||
{
|
||||
struct ts_filter_mean *priv;
|
||||
int *v;
|
||||
int n;
|
||||
|
||||
priv = kzalloc(sizeof(struct ts_filter_mean), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
|
||||
priv->tsf.count_coords = count_coords;
|
||||
priv->config = container_of(conf,
|
||||
struct ts_filter_mean_configuration,
|
||||
config);
|
||||
|
||||
BUG_ON(priv->config->length <= 0);
|
||||
|
||||
v = kmalloc(priv->config->length * sizeof(int) * count_coords,
|
||||
GFP_KERNEL);
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
for (n = 0; n < count_coords; n++) {
|
||||
priv->fifo[n] = v;
|
||||
v += priv->config->length;
|
||||
}
|
||||
|
||||
ts_filter_mean_clear(&priv->tsf);
|
||||
|
||||
dev_info(&pdev->dev, "Created Mean filter len:%d coords:%d\n",
|
||||
priv->config->length, count_coords);
|
||||
|
||||
return &priv->tsf;
|
||||
}
|
||||
|
||||
static void ts_filter_mean_destroy(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
|
||||
kfree(priv->fifo[0]); /* first guy has pointer from kmalloc */
|
||||
kfree(tsf);
|
||||
}
|
||||
|
||||
static void ts_filter_mean_clear(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
|
||||
priv->count = 0;
|
||||
priv->curr = 0;
|
||||
priv->ready = 0;
|
||||
memset(priv->sum, 0, tsf->count_coords * sizeof(int));
|
||||
}
|
||||
|
||||
static int ts_filter_mean_process(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
int n;
|
||||
|
||||
BUG_ON(priv->ready);
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++) {
|
||||
priv->sum[n] += coords[n];
|
||||
priv->fifo[n][priv->curr] = coords[n];
|
||||
}
|
||||
|
||||
if (priv->count + 1 == priv->config->length)
|
||||
priv->ready = 1;
|
||||
else
|
||||
priv->count++;
|
||||
|
||||
priv->curr = (priv->curr + 1) % priv->config->length;
|
||||
|
||||
return 0; /* No error. */
|
||||
}
|
||||
|
||||
static int ts_filter_mean_haspoint(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
|
||||
return priv->ready;
|
||||
}
|
||||
|
||||
static void ts_filter_mean_getpoint(struct ts_filter *tsf, int *point)
|
||||
{
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
int n;
|
||||
|
||||
BUG_ON(!priv->ready);
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++) {
|
||||
point[n] = priv->sum[n];
|
||||
priv->sum[n] -= priv->fifo[n][priv->curr];
|
||||
}
|
||||
|
||||
priv->ready = 0;
|
||||
}
|
||||
|
||||
static void ts_filter_mean_scale(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
int n;
|
||||
struct ts_filter_mean *priv = ts_filter_to_filter_mean(tsf);
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++) {
|
||||
coords[n] += priv->config->length >> 1; /* Rounding. */
|
||||
coords[n] /= priv->config->length;
|
||||
}
|
||||
}
|
||||
|
||||
const struct ts_filter_api ts_filter_mean_api = {
|
||||
.create = ts_filter_mean_create,
|
||||
.destroy = ts_filter_mean_destroy,
|
||||
.clear = ts_filter_mean_clear,
|
||||
.process = ts_filter_mean_process,
|
||||
.scale = ts_filter_mean_scale,
|
||||
.haspoint = ts_filter_mean_haspoint,
|
||||
.getpoint = ts_filter_mean_getpoint,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ts_filter_mean_api);
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2008 Andy Green <andy@openmoko.com>
|
||||
*
|
||||
*
|
||||
* Median averaging stuff. We sort incoming raw samples into an array of
|
||||
* MEDIAN_SIZE length, discarding the oldest sample each time once we are full.
|
||||
* We then return the sum of the middle three samples for X and Y. It means
|
||||
* the final result must be divided by (3 * scaling factor) to correct for
|
||||
* avoiding the repeated /3.
|
||||
*
|
||||
* This strongly rejects brief excursions away from a central point that is
|
||||
* sticky in time compared to the excursion duration.
|
||||
*
|
||||
* Thanks to Dale Schumacher (who wrote some example code) and Carl-Daniel
|
||||
* Halifinger who pointed out this would be a good method.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/touchscreen/ts_filter_median.h>
|
||||
|
||||
struct ts_filter_median {
|
||||
/* Private configuration. */
|
||||
struct ts_filter_median_configuration *config;
|
||||
/* Generic Filter API. */
|
||||
struct ts_filter tsf;
|
||||
|
||||
/* Count raw samples we get. */
|
||||
int samples_count;
|
||||
/*
|
||||
* Remember the last coordinates we got in order to know if
|
||||
* we are moving slow or fast.
|
||||
*/
|
||||
int last_issued[MAX_TS_FILTER_COORDS];
|
||||
/* How many samples in the sort buffer are valid. */
|
||||
int valid;
|
||||
/* Samples taken for median in sorted form. */
|
||||
int *sort[MAX_TS_FILTER_COORDS];
|
||||
/* Samples taken for median. */
|
||||
int *fifo[MAX_TS_FILTER_COORDS];
|
||||
/* Where we are in the fifo sample memory. */
|
||||
int pos;
|
||||
/* Do we have a sample to deliver? */
|
||||
int ready;
|
||||
};
|
||||
|
||||
#define ts_filter_to_filter_median(f) \
|
||||
container_of(f, struct ts_filter_median, tsf)
|
||||
|
||||
|
||||
static void ts_filter_median_insert(int *p, int sample, int count)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Search through what we got so far to find where to put sample. */
|
||||
for (n = 0; n < count; n++)
|
||||
if (sample < p[n]) { /* We met somebody bigger than us? */
|
||||
/* Starting from the end, push bigger guys down one. */
|
||||
for (count--; count >= n; count--)
|
||||
p[count + 1] = p[count];
|
||||
p[n] = sample; /* Put us in place of first bigger. */
|
||||
return;
|
||||
}
|
||||
|
||||
p[count] = sample; /* Nobody was bigger than us, add us on the end. */
|
||||
}
|
||||
|
||||
static void ts_filter_median_del(int *p, int value, int count)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
if (p[index] == value) {
|
||||
for (; index < count; index++)
|
||||
p[index] = p[index + 1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ts_filter_median_clear(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf);
|
||||
|
||||
tsfm->pos = 0;
|
||||
tsfm->valid = 0;
|
||||
tsfm->ready = 0;
|
||||
memset(&tsfm->last_issued[0], 1, tsf->count_coords * sizeof(int));
|
||||
}
|
||||
|
||||
static struct ts_filter *ts_filter_median_create(
|
||||
struct platform_device *pdev,
|
||||
const struct ts_filter_configuration *conf,
|
||||
int count_coords)
|
||||
{
|
||||
int *p;
|
||||
int n;
|
||||
struct ts_filter_median *tsfm = kzalloc(sizeof(struct ts_filter_median),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!tsfm)
|
||||
return NULL;
|
||||
|
||||
tsfm->config = container_of(conf,
|
||||
struct ts_filter_median_configuration,
|
||||
config);
|
||||
|
||||
tsfm->tsf.count_coords = count_coords;
|
||||
|
||||
tsfm->config->midpoint = (tsfm->config->extent >> 1) + 1;
|
||||
|
||||
p = kmalloc(2 * count_coords * sizeof(int) * (tsfm->config->extent + 1),
|
||||
GFP_KERNEL);
|
||||
if (!p) {
|
||||
kfree(tsfm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (n = 0; n < count_coords; n++) {
|
||||
tsfm->sort[n] = p;
|
||||
p += tsfm->config->extent + 1;
|
||||
tsfm->fifo[n] = p;
|
||||
p += tsfm->config->extent + 1;
|
||||
}
|
||||
|
||||
ts_filter_median_clear(&tsfm->tsf);
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
"Created Median filter len:%d coords:%d dec_threshold:%d\n",
|
||||
tsfm->config->extent, count_coords,
|
||||
tsfm->config->decimation_threshold);
|
||||
|
||||
return &tsfm->tsf;
|
||||
}
|
||||
|
||||
static void ts_filter_median_destroy(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf);
|
||||
|
||||
kfree(tsfm->sort[0]); /* First guy has pointer from kmalloc. */
|
||||
kfree(tsf);
|
||||
}
|
||||
|
||||
static void ts_filter_median_scale(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++)
|
||||
coords[n] = (coords[n] + 2) / 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give us the raw sample data coords, and if we return 1 then you can
|
||||
* get a filtered coordinate from coords. If we return 0 you didn't
|
||||
* fill all the filters with samples yet.
|
||||
*/
|
||||
|
||||
static int ts_filter_median_process(struct ts_filter *tsf, int *coords)
|
||||
{
|
||||
struct ts_filter_median *tsfm = ts_filter_to_filter_median(tsf);
|
||||
int n;
|
||||
int movement = 1;
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++) {
|
||||
/* Grab copy in insertion order to remove when oldest. */
|
||||
tsfm->fifo[n][tsfm->pos] = coords[n];
|
||||
/* Insert these samples in sorted order in the median arrays. */
|
||||
ts_filter_median_insert(tsfm->sort[n], coords[n], tsfm->valid);
|
||||
}
|
||||
/* Move us on in the fifo. */
|
||||
if (++tsfm->pos == (tsfm->config->extent + 1))
|
||||
tsfm->pos = 0;
|
||||
|
||||
/* Have we finished a median sampling? */
|
||||
if (++tsfm->valid < tsfm->config->extent)
|
||||
goto process_exit; /* No valid sample to use. */
|
||||
|
||||
BUG_ON(tsfm->valid != tsfm->config->extent);
|
||||
|
||||
tsfm->valid--;
|
||||
|
||||
/*
|
||||
* Sum the middle 3 in the median sorted arrays. We don't divide back
|
||||
* down which increases the sum resolution by a factor of 3 until the
|
||||
* scale API function is called.
|
||||
*/
|
||||
for (n = 0; n < tsf->count_coords; n++)
|
||||
/* Perform the deletion of the oldest sample. */
|
||||
ts_filter_median_del(tsfm->sort[n], tsfm->fifo[n][tsfm->pos],
|
||||
tsfm->valid);
|
||||
|
||||
tsfm->samples_count--;
|
||||
if (tsfm->samples_count >= 0)
|
||||
goto process_exit;
|
||||
|
||||
for (n = 0; n < tsf->count_coords; n++) {
|
||||
/* Give the coordinate result from summing median 3. */
|
||||
coords[n] = tsfm->sort[n][tsfm->config->midpoint - 1] +
|
||||
tsfm->sort[n][tsfm->config->midpoint] +
|
||||
tsfm->sort[n][tsfm->config->midpoint + 1];
|
||||
|
||||
movement += abs(tsfm->last_issued[n] - coords[n]);
|
||||
}
|
||||
|
||||
if (movement > tsfm->config->decimation_threshold) /* Moving fast. */
|
||||
tsfm->samples_count = tsfm->config->decimation_above;
|
||||
else
|
||||
tsfm->samples_count = tsfm->config->decimation_below;
|
||||
|
||||
memcpy(&tsfm->last_issued[0], coords, tsf->count_coords * sizeof(int));
|
||||
|
||||
tsfm->ready = 1;
|
||||
|
||||
process_exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts_filter_median_haspoint(struct ts_filter *tsf)
|
||||
{
|
||||
struct ts_filter_median *priv = ts_filter_to_filter_median(tsf);
|
||||
|
||||
return priv->ready;
|
||||
}
|
||||
|
||||
static void ts_filter_median_getpoint(struct ts_filter *tsf, int *point)
|
||||
{
|
||||
struct ts_filter_median *priv = ts_filter_to_filter_median(tsf);
|
||||
|
||||
BUG_ON(!priv->ready);
|
||||
|
||||
memcpy(point, &priv->last_issued[0], tsf->count_coords * sizeof(int));
|
||||
|
||||
priv->ready = 0;
|
||||
}
|
||||
|
||||
const struct ts_filter_api ts_filter_median_api = {
|
||||
.create = ts_filter_median_create,
|
||||
.destroy = ts_filter_median_destroy,
|
||||
.clear = ts_filter_median_clear,
|
||||
.process = ts_filter_median_process,
|
||||
.scale = ts_filter_median_scale,
|
||||
.haspoint = ts_filter_median_haspoint,
|
||||
.getpoint = ts_filter_median_getpoint,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ts_filter_median_api);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue