FEATURES:=jffs2
CFLAGS:=-O2 -pipe -march=armv4t -mtune=arm920t -funit-at-a-time
-LINUX_VERSION:=2.6.29
+LINUX_VERSION:=2.6.30-rc6
DEVICE_TYPE=phone
--- /dev/null
+/*
+ * 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/hardware.h>
+#include <asm/mach-types.h>
+#include <linux/gta02-shadow.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);
+
+ gta02_gpb_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);
+ }
+
+ gta02_gpb_setpin(GTA02_GPIO_BT_EN, on);
+}
+
+
+static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+ struct device *dev = data;
+ unsigned long on = (state == RFKILL_STATE_ON);
+
+ __gta02_pm_bt_toggle_radio(dev, on);
+
+ return 0;
+}
+
+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")) {
+ enum rfkill_state state = on ? RFKILL_STATE_ON : RFKILL_STATE_OFF;
+ bt_rfkill_toggle_radio(dev, state);
+ bt_data->rfkill->state = state;
+
+ __gta02_pm_bt_toggle_radio(dev, on);
+ } else if (!strcmp(attr->attr.name, "reset")) {
+ /* reset is low-active, so we need to invert */
+ gta02_gpb_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 */
+ gta02_gpb_setpin(GTA02_GPIO_BT_EN, 0);
+
+ rfkill = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH);
+
+ rfkill->name = pdev->name;
+ rfkill->data = &pdev->dev;
+ rfkill->state = RFKILL_STATE_OFF;
+ rfkill->toggle_radio = bt_rfkill_toggle_radio;
+
+ ret = rfkill_register(rfkill);
+ if (ret) {
+ 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_unregister(bt_data->rfkill);
+ rfkill_free(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);
--- /dev/null
+/*
+ * 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/cpu.h>
+
+#include <asm/mach-types.h>
+
+#include <linux/gta02-shadow.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_GPH4, S3C2410_GPH4_TXD1);
+ /* remove pulldown now it won't be floating any more */
+ s3c2410_gpio_pullup(S3C2410_GPH5, 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_GPH4, S3C2410_GPH4_OUTP);
+ s3c2410_gpio_setpin(S3C2410_GPH4, 0);
+ /* don't let RX from unpowered GPS float */
+ s3c2410_gpio_pullup(S3C2410_GPH5, 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_GPH4, S3C2410_GPH4_OUTP);
+ s3c2410_gpio_setpin(S3C2410_GPH4, 0);
+ /* don't let RX from unpowered GPS float */
+ s3c2410_gpio_pullup(S3C2410_GPH5, 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>");
--- /dev/null
+/*
+ * 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 <linux/gta02-shadow.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);
+
+struct gta02pm_priv {
+ int gpio_ndl_gsm;
+};
+
+static struct gta02pm_priv gta02_gsm;
+
+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_GPH1) == 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) {
+ /*
+ * Do not drive into powered-down GSM side
+ * GTA02 only, because on GTA01 maybe serial
+ * is used otherwise.
+ */
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPIO_INPUT);
+ s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPIO_INPUT);
+
+ pcf50633_gpio_set(gta02_pcf, PCF50633_GPIO2, 0);
+
+ return;
+ }
+
+ /* allow UART to talk to GSM side now we will power it */
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_nRTS0);
+ s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPH2_TXD0);
+
+ pcf50633_gpio_set(gta02_pcf, PCF50633_GPIO2, 7);
+
+ msleep(100);
+
+ /*
+ * workaround for calypso firmware moko10 and earlier,
+ * without this it will leave IRQ line high after
+ * booting
+ */
+ s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
+ msleep(1000);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, 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_GPH1, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
+ } else
+ s3c2410_gpio_cfgpin(S3C2410_GPH1, 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_GPH1) == 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_GPH1) == 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. */
+
+ 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:
+ /* TODO: fail */
+ dev_warn(&pdev->dev, "Unknown Neo1973 Revision 0x%x, "
+ "some PM features not available!!!\n",
+ system_rev);
+ break;
+ }
+
+ /* 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");
--- /dev/null
+/*
+ * 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 <linux/gta02-shadow.h>
+
+#include <mach/gta02.h>
+#include <mach/gta02-pm-wlan.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.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_toggle_radio(void *data, enum rfkill_state state)
+{
+ struct device *dev = data;
+ int on = state == RFKILL_STATE_UNBLOCKED;
+ int res = 0;
+
+ dev_dbg(dev, "gta02_wlan_toggle_radio: state %d (%p)\n",
+ state, gta02_wlan_rfkill_cb);
+ mutex_lock(>a02_wlan_rfkill_lock);
+ if (gta02_wlan_rfkill_cb)
+ res = gta02_wlan_rfkill_cb(gta02_wlan_rfkill_user, on);
+ if (!res)
+ gta02_wlan_rfkill_on = on;
+ mutex_unlock(>a02_wlan_rfkill_lock);
+ return res;
+}
+
+
+/* ----- 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 error;
+
+ 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_allocate(&pdev->dev, RFKILL_TYPE_WLAN);
+ rfkill->name = "ar6000";
+ rfkill->data = &pdev->dev;
+ rfkill->state = default_state ? RFKILL_STATE_ON : RFKILL_STATE_OFF;
+ /*
+ * 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;
+ rfkill->toggle_radio = gta02_wlan_toggle_radio;
+
+ error = rfkill_register(rfkill);
+ if (error) {
+ rfkill_free(rfkill);
+ return error;
+ }
+
+ 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_unregister(rfkill);
+ rfkill_free(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");
--- /dev/null
+/*
+ * Common utility code for GTA02
+ *
+ * Copyright (C) 2008 by Openmoko, Inc.
+ * Author: Holger Hans Peter Freyther <freyther@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 as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/gpio.h>
+#include <mach/regs-gpio.h>
+#include <linux/gta02-shadow.h>
+
+/**
+ * Shadow GPIO bank B handling. For the LEDs we need to keep track of the state
+ * in software. The s3c2410_gpio_setpin must not be used for GPIOs on bank B
+ */
+static unsigned long gpb_mask;
+static unsigned long gpb_state;
+
+void gta02_gpb_add_shadow_gpio(unsigned int gpio)
+{
+ unsigned long offset = S3C2410_GPIO_OFFSET(gpio);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ gpb_mask |= 1L << offset;
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gta02_gpb_add_shadow_gpio);
+
+static void set_shadow_gpio(unsigned long offset, unsigned int value)
+{
+ unsigned long state = value != 0;
+
+ gpb_state &= ~(1L << offset);
+ gpb_state |= state << offset;
+}
+
+void gta02_gpb_setpin(unsigned int pin, unsigned to)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(S3C2410_GPB0);
+ unsigned long offset = S3C2410_GPIO_OFFSET(pin);
+ unsigned long flags;
+ unsigned long dat;
+
+ BUG_ON(base != S3C24XX_GPIO_BASE(pin));
+
+ local_irq_save(flags);
+ dat = __raw_readl(base + 0x04);
+
+ /* Add the shadow values */
+ dat &= ~gpb_mask;
+ dat |= gpb_state;
+
+ /* Do the operation like s3c2410_gpio_setpin */
+ dat &= ~(1L << offset);
+ dat |= to << offset;
+
+ /* Update the shadow state */
+ if ((1L << offset) & gpb_mask)
+ set_shadow_gpio(offset, to);
+
+ __raw_writel(dat, base + 0x04);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gta02_gpb_setpin);
--- /dev/null
+extern int gta02_pm_gps_is_on(void);
--- /dev/null
+extern int gta_gsm_interrupts;
--- /dev/null
+#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 */
--- /dev/null
+#ifndef _GTA02_H
+#define _GTA02_H
+
+#include <mach/regs-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_GPA13 /* v1 + v2 + v3 only */
+
+#define GTA02_GPIO_PWR_LED1 S3C2410_GPB0
+#define GTA02_GPIO_PWR_LED2 S3C2410_GPB1
+#define GTA02_GPIO_AUX_LED S3C2410_GPB2
+#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB3
+#define GTA02_GPIO_MODEM_RST S3C2410_GPB5
+#define GTA02_GPIO_BT_EN S3C2410_GPB6
+#define GTA02_GPIO_MODEM_ON S3C2410_GPB7
+#define GTA02_GPIO_EXTINT8 S3C2410_GPB8
+#define GTA02_GPIO_USB_PULLUP S3C2410_GPB9
+
+#define GTA02_GPIO_PIO5 S3C2410_GPC5 /* v3 + v4 only */
+#define GTA02v3_GPIO_nG1_CS S3C2410_GPD12 /* v3 + v4 only */
+#define GTA02v3_GPIO_nG2_CS S3C2410_GPD13 /* v3 + v4 only */
+#define GTA02v5_GPIO_HDQ S3C2410_GPD14 /* v5 + */
+
+#define GTA02_GPIO_nG1_INT S3C2410_GPF0
+#define GTA02_GPIO_IO1 S3C2410_GPF1
+#define GTA02_GPIO_PIO_2 S3C2410_GPF2 /* v2 + v3 + v4 only */
+#define GTA02_GPIO_JACK_INSERT S3C2410_GPF4
+#define GTA02_GPIO_WLAN_GPIO1 S3C2410_GPF5 /* v2 + v3 + v4 only */
+#define GTA02_GPIO_AUX_KEY S3C2410_GPF6
+#define GTA02_GPIO_HOLD_KEY S3C2410_GPF7
+
+#define GTA02_GPIO_3D_IRQ S3C2410_GPG4
+#define GTA02v2_GPIO_nG2_INT S3C2410_GPG8 /* v2 + v3 + v4 only */
+#define GTA02v3_GPIO_nUSB_OC S3C2410_GPG9 /* v3 + v4 only */
+#define GTA02v3_GPIO_nUSB_FLT S3C2410_GPG10 /* v3 + v4 only */
+#define GTA02v3_GPIO_nGSM_OC S3C2410_GPG11 /* 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_GPC13
+#define GTA02_PCB_ID1_1 S3C2410_GPC15
+#define GTA02_PCB_ID1_2 S3C2410_GPD0
+#define GTA02_PCB_ID2_0 S3C2410_GPD3
+#define GTA02_PCB_ID2_1 S3C2410_GPD4
+
+int gta02_get_pcb_revision(void);
+
+extern struct pcf50633 *gta02_pcf;
+
+#endif /* _GTA02_H */
--- /dev/null
+/*
+ * linux/arch/arm/mach-s3c2442/mach-gta02.c
+ *
+ * S3C2442 Machine Support for the Openmoko Freerunner (GTA02)
+ *
+ * Copyright (C) 2006-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 as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/glamo.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/mmc/host.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/mbc.h>
+#include <linux/mfd/pcf50633/adc.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/mfd/pcf50633/pmic.h>
+
+#include <linux/lis302dl.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/fb.h>
+#include <mach/mci.h>
+#include <mach/ts.h>
+#include <mach/spi.h>
+#include <mach/spi-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/spi-gpio.h>
+#include <plat/pwm.h>
+#include <mach/cpu.h>
+
+#include <mach/gta02.h>
+
+#include <plat/regs-serial.h>
+#include <plat/nand.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
+#include <plat/usb-control.h>
+#include <plat/regs-timer.h>
+
+#include <mach/gta02-pm-gsm.h>
+#include <mach/gta02-pm-gps.h>
+#include <mach/gta02-pm-wlan.h>
+
+#include <linux/jbt6k74.h>
+#include <linux/glamofb.h>
+
+#include <linux/hdq.h>
+#include <linux/bq27000_battery.h>
+
+#include <linux/touchscreen/ts_filter_chain.h>
+#ifdef CONFIG_TOUCHSCREEN_FILTER
+#include <linux/touchscreen/ts_filter_linear.h>
+#include <linux/touchscreen/ts_filter_mean.h>
+#include <linux/touchscreen/ts_filter_median.h>
+#include <linux/touchscreen/ts_filter_group.h>
+#endif
+
+#include <asm/fiq.h>
+
+#include <linux/gta02-vibrator.h>
+#include <linux/gta02-shadow.h>
+
+/* arbitrates which sensor IRQ owns the shared SPI bus */
+static spinlock_t motion_irq_lock;
+
+
+/* -------------------------------------------------------------------------------
+ * GTA02 FIQ related
+ *
+ * Calls into vibrator and hdq and based on the return values
+ * determines if we the FIQ source be kept alive
+ */
+
+#define DIVISOR_FROM_US(x) ((x) << 3)
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+#define FIQ_DIVISOR_HDQ DIVISOR_FROM_US(HDQ_SAMPLE_PERIOD_US)
+extern int hdq_fiq_handler(void);
+#endif
+
+#ifdef CONFIG_LEDS_GTA02_VIBRATOR
+#define FIQ_DIVISOR_VIBRATOR DIVISOR_FROM_US(100)
+extern int gta02_vibrator_fiq_handler(void);
+#endif
+
+#if defined(CONFIG_LEDS_GTA02_VIBRATOR) || defined(CONFIG_HDQ_GPIO_BITBANG)
+
+/* Global data related to our fiq source */
+static u32 gta02_fiq_ack_mask;
+static struct s3c2410_pwm gta02_fiq_pwm_timer;
+static u16 gta02_fiq_timer_index;
+static int gta02_fiq_irq;
+
+static void gta02_fiq_handler(void)
+{
+ u16 divisor = 0xffff;
+
+ /* Vibrator servicing */
+
+ /* disable further timer interrupts if nobody has any work
+ * or adjust rate according to who still has work
+ *
+ * CAUTION: it means forground code must disable FIQ around
+ * its own non-atomic S3C2410_INTMSK changes... not common
+ * thankfully and taken care of by the fiq-basis patch
+ */
+
+#ifdef CONFIG_LEDS_GTA02_VIBRATOR
+ if (gta02_vibrator_fiq_handler())
+ divisor = FIQ_DIVISOR_VIBRATOR;
+#endif
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+ if (hdq_fiq_handler())
+ divisor = FIQ_DIVISOR_HDQ;
+#endif
+
+ if (divisor == 0xffff) /* mask the fiq irq source */
+ __raw_writel(__raw_readl(S3C2410_INTMSK) | gta02_fiq_ack_mask,
+ S3C2410_INTMSK);
+ else /* still working, maybe at a different rate */
+ __raw_writel(divisor, S3C2410_TCNTB(gta02_fiq_timer_index));
+
+ __raw_writel(gta02_fiq_ack_mask, S3C2410_SRCPND);
+}
+
+static void gta02_fiq_kick(void)
+{
+ unsigned long flags;
+ u32 tcon;
+
+ /* we have to take care about FIQ because this modification is
+ * non-atomic, FIQ could come in after the read and before the
+ * writeback and its changes to the register would be lost
+ * (platform INTMSK mod code is taken care of already)
+ */
+ local_save_flags(flags);
+ local_fiq_disable();
+ /* allow FIQs to resume */
+ __raw_writel(__raw_readl(S3C2410_INTMSK) &
+ ~(1 << (gta02_fiq_irq - S3C2410_CPUIRQ_OFFSET)),
+ S3C2410_INTMSK);
+ tcon = __raw_readl(S3C2410_TCON) & ~S3C2410_TCON_T3START;
+ /* fake the timer to a count of 1 */
+ __raw_writel(1, S3C2410_TCNTB(gta02_fiq_timer_index));
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
+ S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3START, S3C2410_TCON);
+ local_irq_restore(flags);
+}
+
+static int gta02_fiq_enable(void)
+{
+ int irq_index_fiq = IRQ_TIMER3;
+ int rc = 0;
+
+ local_fiq_disable();
+
+ gta02_fiq_irq = irq_index_fiq;
+ gta02_fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
+ gta02_fiq_timer_index = (irq_index_fiq - IRQ_TIMER0);
+
+ /* set up the timer to operate as a pwm device */
+
+ rc = s3c2410_pwm_init(>a02_fiq_pwm_timer);
+ if (rc)
+ goto bail;
+
+ gta02_fiq_pwm_timer.timerid = PWM0 + gta02_fiq_timer_index;
+ gta02_fiq_pwm_timer.prescaler = (6 - 1) / 2;
+ gta02_fiq_pwm_timer.divider = S3C2410_TCFG1_MUX3_DIV2;
+ /* default rate == ~32us */
+ gta02_fiq_pwm_timer.counter = gta02_fiq_pwm_timer.comparer = 3000;
+
+ rc = s3c2410_pwm_enable(>a02_fiq_pwm_timer);
+ if (rc)
+ goto bail;
+
+ s3c2410_pwm_start(>a02_fiq_pwm_timer);
+
+ /* let our selected interrupt be a magic FIQ interrupt */
+ __raw_writel(gta02_fiq_ack_mask, S3C2410_INTMOD);
+
+ /* it's ready to go as soon as we unmask the source in S3C2410_INTMSK */
+ local_fiq_enable();
+
+ set_fiq_c_handler(gta02_fiq_handler);
+
+ return 0;
+
+bail:
+ printk(KERN_ERR "Could not initialize FIQ for GTA02: %d\n", rc);
+
+ return rc;
+}
+
+static void gta02_fiq_disable(void)
+{
+ __raw_writel(0, S3C2410_INTMOD);
+ local_fiq_disable();
+ gta02_fiq_irq = 0; /* no active source interrupt now either */
+
+}
+/* -------------------- /GTA02 FIQ Handler ------------------------------------- */
+
+#endif
+
+/*
+ * this gets called every 1ms when we paniced.
+ */
+
+static long gta02_panic_blink(long count)
+{
+ long delay = 0;
+ static long last_blink;
+ static char led;
+
+ if (count - last_blink < 100) /* 200ms period, fast blink */
+ return 0;
+
+ led ^= 1;
+ s3c2410_gpio_cfgpin(GTA02_GPIO_AUX_LED, S3C2410_GPIO_OUTPUT);
+ gta02_gpb_setpin(GTA02_GPIO_AUX_LED, led);
+
+ last_blink = count;
+ return delay;
+}
+
+
+/**
+ * returns PCB revision information in b9,b8 and b2,b1,b0
+ * Pre-GTA02 A6 returns 0x000
+ * GTA02 A6 returns 0x101
+ * ...
+ */
+
+int gta02_get_pcb_revision(void)
+{
+ int n;
+ int u = 0;
+ static unsigned long pinlist[] = {
+ GTA02_PCB_ID1_0,
+ GTA02_PCB_ID1_1,
+ GTA02_PCB_ID1_2,
+ GTA02_PCB_ID2_0,
+ GTA02_PCB_ID2_1,
+ };
+ static int pin_offset[] = {
+ 0, 1, 2, 8, 9
+ };
+
+ for (n = 0 ; n < ARRAY_SIZE(pinlist); n++) {
+ /*
+ * set the PCB version GPIO to be pulled-down input
+ * force low briefly first
+ */
+ s3c2410_gpio_cfgpin(pinlist[n], S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_setpin(pinlist[n], 0);
+ /* misnomer: it is a pullDOWN in 2442 */
+ s3c2410_gpio_pullup(pinlist[n], 1);
+ s3c2410_gpio_cfgpin(pinlist[n], S3C2410_GPIO_INPUT);
+
+ udelay(10);
+
+ if (s3c2410_gpio_getpin(pinlist[n]))
+ u |= 1 << pin_offset[n];
+
+ /*
+ * when not being interrogated, all of the revision GPIO
+ * are set to output HIGH without pulldown so no current flows
+ * if they are NC or pulled up.
+ */
+ s3c2410_gpio_setpin(pinlist[n], 1);
+ s3c2410_gpio_cfgpin(pinlist[n], S3C2410_GPIO_OUTPUT);
+ /* misnomer: it is a pullDOWN in 2442 */
+ s3c2410_gpio_pullup(pinlist[n], 0);
+ }
+
+ return u;
+}
+
+struct platform_device gta02_resume_reason_device = {
+ .name = "gta02-resume",
+ .num_resources = 0,
+};
+
+static struct map_desc gta02_iodesc[] __initdata = {
+ {
+ .virtual = 0xe0000000,
+ .pfn = __phys_to_pfn(S3C2410_CS3+0x01000000),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ },
+};
+
+#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg gta02_uartcfgs[] = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+
+};
+
+struct pcf50633 *gta02_pcf;
+
+#ifdef CONFIG_CHARGER_PCF50633
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+static int gta02_get_charger_online_status(void)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+
+ return pcf50633_mbc_get_status(pcf) & PCF50633_MBC_USB_ONLINE;
+}
+
+static int gta02_get_charger_active_status(void)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+
+ return pcf50633_mbc_get_status(pcf) & PCF50633_MBC_USB_ACTIVE;
+}
+#endif
+
+#define ADC_NOM_CHG_DETECT_1A 6
+#define ADC_NOM_CHG_DETECT_USB 43
+
+static void
+gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
+{
+ int ma;
+
+ /* Interpret charger type */
+ if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
+
+ /* Stop GPO driving out now that we have a IA charger */
+ pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
+
+ ma = 1000;
+ } else
+ ma = 100;
+
+ pcf50633_mbc_usb_curlim_set(pcf, ma);
+}
+
+static struct delayed_work gta02_charger_work;
+static int gta02_usb_vbus_draw;
+
+static void gta02_charger_worker(struct work_struct *work)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+
+ if (gta02_usb_vbus_draw) {
+ pcf50633_mbc_usb_curlim_set(pcf, gta02_usb_vbus_draw);
+ return;
+ } else {
+#ifdef CONFIG_PCF50633_ADC
+ pcf50633_adc_async_read(pcf,
+ PCF50633_ADCC1_MUX_ADCIN1,
+ PCF50633_ADCC1_AVERAGE_16,
+ gta02_configure_pmu_for_charger, NULL);
+#else
+ /* If the PCF50633 ADC is disabled we fallback to a 100mA limit for safety. */
+ pcf50633_mbc_usb_curlim_set(pcf, 100);
+#endif
+ return;
+ }
+}
+
+#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
+static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
+{
+ if (irq == PCF50633_IRQ_USBINS) {
+ schedule_delayed_work(>a02_charger_work,
+ GTA02_CHARGER_CONFIGURE_TIMEOUT);
+ return;
+ } else if (irq == PCF50633_IRQ_USBREM) {
+ cancel_delayed_work_sync(>a02_charger_work);
+ gta02_usb_vbus_draw = 0;
+ }
+}
+
+static void gta02_pmu_force_shutdown(struct pcf50633 *pcf)
+{
+ pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_OOCSHDWN,
+ PCF50633_OOCSHDWN_GOSTDBY, PCF50633_OOCSHDWN_GOSTDBY);
+}
+
+
+static void gta02_udc_vbus_draw(unsigned int ma)
+{
+ if (!gta02_pcf)
+ return;
+
+ gta02_usb_vbus_draw = ma;
+
+ schedule_delayed_work(>a02_charger_work,
+ GTA02_CHARGER_CONFIGURE_TIMEOUT);
+}
+
+static int gta02_udc_vbus_status(void)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+ if (!gta02_pcf)
+ return -ENODEV;
+
+ return !!(pcf50633_mbc_get_status(pcf) & PCF50633_MBC_USB_ONLINE);
+}
+
+#else /* !CONFIG_CHARGER_PCF50633 */
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+#define gta02_get_charger_online_status NULL
+#define gta02_get_charger_active_status NULL
+#endif
+#define gta02_pmu_event_callback NULL
+#define gta02_udc_vbus_draw NULL
+#define gta02_udc_vbus_status NULL
+#endif
+
+
+static struct platform_device gta02_pm_gps_dev = {
+ .name = "gta02-pm-gps",
+};
+
+static struct platform_device gta02_pm_bt_dev = {
+ .name = "gta02-pm-bt",
+};
+
+static struct platform_device gta02_pm_gsm_dev = {
+ .name = "gta02-pm-gsm",
+};
+
+static struct platform_device gta02_pm_wlan_dev = {
+ .name = "gta02-pm-wlan",
+};
+
+/* this is called when pc50633 is probed, unfortunately quite late in the
+ * day since it is an I2C bus device. Here we can belatedly define some
+ * platform devices with the advantage that we can mark the pcf50633 as the
+ * parent. This makes them get suspended and resumed with their parent
+ * the pcf50633 still around.
+ */
+
+static struct platform_device gta02_glamo_dev;
+static void mangle_glamo_res_by_system_rev(void);
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
+static void gta02_pmu_regulator_registered(struct pcf50633 *pcf, int id);
+
+static struct regulator_consumer_supply ldo4_consumers[] = {
+ {
+ .dev = >a02_pm_bt_dev.dev,
+ .supply = "BT_3V2",
+ },
+};
+
+static struct regulator_consumer_supply ldo5_consumers[] = {
+ {
+ .dev = >a02_pm_gps_dev.dev,
+ .supply = "RF_3V",
+ },
+};
+
+/*
+ * We need this dummy thing to fill the regulator consumers
+ */
+static struct platform_device gta02_mmc_dev = {
+ /* details filled in by glamo core */
+};
+
+static struct regulator_consumer_supply hcldo_consumers[] = {
+ {
+ .dev = >a02_mmc_dev.dev,
+ .supply = "SD_3V3",
+ },
+};
+
+static char *gta02_batteries[] = {
+ "battery",
+};
+
+#ifdef CONFIG_CHARGER_PCF50633
+
+struct pcf50633_platform_data gta02_pcf_pdata = {
+ .resumers = {
+ [0] = PCF50633_INT1_USBINS |
+ PCF50633_INT1_USBREM |
+ PCF50633_INT1_ALARM,
+ [1] = PCF50633_INT2_ONKEYF,
+ [2] = PCF50633_INT3_ONKEY1S,
+ [3] = PCF50633_INT4_LOWSYS |
+ PCF50633_INT4_LOWBAT |
+ PCF50633_INT4_HIGHTMP,
+ },
+
+ .batteries = gta02_batteries,
+ .num_batteries = ARRAY_SIZE(gta02_batteries),
+ .charging_restart_interval = (900 * HZ),
+ .chg_ref_current_ma = 1000,
+
+ .reg_init_data = {
+ [PCF50633_REGULATOR_AUTO] = {
+ .constraints = {
+ .name = "IO_3V3",
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .boot_on = 1,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_DOWN1] = {
+ .constraints = {
+ .name = "CORE_1V3",
+ .min_uV = 1300000,
+ .max_uV = 1600000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .boot_on = 1,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_DOWN2] = {
+ .constraints = {
+ .name = "IO_1V8",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .boot_on = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_HCLDO] = {
+ .constraints = {
+ .name = "SD_3V3",
+ .min_uV = 2000000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = hcldo_consumers,
+ },
+ [PCF50633_REGULATOR_LDO1] = {
+ .constraints = {
+ .name = "GSENSOR_3V3",
+ .min_uV = 1300000,
+ .max_uV = 1300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_LDO2] = {
+ .constraints = {
+ .name = "CODEC_3V3",
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_LDO3] = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_LDO4] = {
+ .constraints = {
+ .name = "BT_3V2",
+ .min_uV = 3200000,
+ .max_uV = 3200000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = ldo4_consumers,
+ },
+ [PCF50633_REGULATOR_LDO5] = {
+ .constraints = {
+ .name = "RF_3V",
+ .min_uV = 1500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = ldo5_consumers,
+ },
+ [PCF50633_REGULATOR_LDO6] = {
+ .constraints = {
+ .name = "LCM_3V",
+ .min_uV = 0,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ },
+ .num_consumer_supplies = 0,
+ },
+ [PCF50633_REGULATOR_MEMLDO] = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+
+ },
+ .probe_done = gta02_pmu_attach_child_devices,
+ .regulator_registered = gta02_pmu_regulator_registered,
+ .mbc_event_callback = gta02_pmu_event_callback,
+ .force_shutdown = gta02_pmu_force_shutdown,
+};
+
+static void mangle_pmu_pdata_by_system_rev(void)
+{
+ struct regulator_init_data *reg_init_data;
+
+ reg_init_data = gta02_pcf_pdata.reg_init_data;
+
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v1_SYSTEM_REV:
+ /* FIXME: this is only in v1 due to wrong PMU variant */
+ reg_init_data[PCF50633_REGULATOR_DOWN2]
+ .constraints.state_mem.enabled = 1;
+ break;
+ case GTA02v2_SYSTEM_REV:
+ case GTA02v3_SYSTEM_REV:
+ case GTA02v4_SYSTEM_REV:
+ case GTA02v5_SYSTEM_REV:
+ case GTA02v6_SYSTEM_REV:
+ reg_init_data[PCF50633_REGULATOR_LDO1]
+ .constraints.min_uV = 3300000;
+ reg_init_data[PCF50633_REGULATOR_LDO1]
+ .constraints.min_uV = 3300000;
+ reg_init_data[PCF50633_REGULATOR_LDO1]
+ .constraints.state_mem.enabled = 0;
+
+ reg_init_data[PCF50633_REGULATOR_LDO5]
+ .constraints.min_uV = 3000000;
+ reg_init_data[PCF50633_REGULATOR_LDO5]
+ .constraints.max_uV = 3000000;
+
+ reg_init_data[PCF50633_REGULATOR_LDO6]
+ .constraints.min_uV = 3000000;
+ reg_init_data[PCF50633_REGULATOR_LDO6]
+ .constraints.max_uV = 3000000;
+ reg_init_data[PCF50633_REGULATOR_LDO6]
+ .constraints.apply_uV = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+#endif
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+/* BQ27000 Battery */
+
+struct bq27000_platform_data bq27000_pdata = {
+ .name = "battery",
+ .rsense_mohms = 20,
+ .hdq_read = hdq_read,
+ .hdq_write = hdq_write,
+ .hdq_initialized = hdq_initialized,
+ .get_charger_online_status = gta02_get_charger_online_status,
+ .get_charger_active_status = gta02_get_charger_active_status
+};
+
+struct platform_device bq27000_battery_device = {
+ .name = "bq27000-battery",
+ .dev = {
+ .platform_data = &bq27000_pdata,
+ },
+};
+
+/* HDQ */
+
+static void gta02_hdq_attach_child_devices(struct device *parent_device)
+{
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v5_SYSTEM_REV:
+ case GTA02v6_SYSTEM_REV:
+ bq27000_battery_device.dev.parent = parent_device;
+ platform_device_register(&bq27000_battery_device);
+ break;
+ default:
+ break;
+ }
+}
+
+static void gta02_hdq_gpio_direction_out(void)
+{
+ s3c2410_gpio_cfgpin(GTA02v5_GPIO_HDQ, S3C2410_GPIO_OUTPUT);
+}
+
+static void gta02_hdq_gpio_direction_in(void)
+{
+ s3c2410_gpio_cfgpin(GTA02v5_GPIO_HDQ, S3C2410_GPIO_INPUT);
+}
+
+static void gta02_hdq_gpio_set_value(int val)
+{
+
+ s3c2410_gpio_setpin(GTA02v5_GPIO_HDQ, val);
+}
+
+static int gta02_hdq_gpio_get_value(void)
+{
+ return s3c2410_gpio_getpin(GTA02v5_GPIO_HDQ);
+}
+
+static struct resource gta02_hdq_resources[] = {
+ [0] = {
+ .start = GTA02v5_GPIO_HDQ,
+ .end = GTA02v5_GPIO_HDQ,
+ },
+};
+
+struct hdq_platform_data gta02_hdq_platform_data = {
+ .attach_child_devices = gta02_hdq_attach_child_devices,
+ .gpio_dir_out = gta02_hdq_gpio_direction_out,
+ .gpio_dir_in = gta02_hdq_gpio_direction_in,
+ .gpio_set = gta02_hdq_gpio_set_value,
+ .gpio_get = gta02_hdq_gpio_get_value,
+
+ .enable_fiq = gta02_fiq_enable,
+ .disable_fiq = gta02_fiq_disable,
+ .kick_fiq = gta02_fiq_kick,
+
+};
+
+struct platform_device gta02_hdq_device = {
+ .name = "hdq",
+ .num_resources = 1,
+ .resource = gta02_hdq_resources,
+ .dev = {
+ .platform_data = >a02_hdq_platform_data,
+ },
+};
+#endif
+
+
+#ifdef CONFIG_LEDS_GTA02_VIBRATOR
+/* vibrator (child of FIQ) */
+
+static struct resource gta02_vibrator_resources[] = {
+ [0] = {
+ .start = GTA02_GPIO_VIBRATOR_ON,
+ .end = GTA02_GPIO_VIBRATOR_ON,
+ },
+};
+struct gta02_vib_platform_data gta02_vib_pdata = {
+ .enable_fiq = gta02_fiq_enable,
+ .disable_fiq = gta02_fiq_disable,
+ .kick_fiq = gta02_fiq_kick,
+};
+
+static struct platform_device gta02_vibrator_dev = {
+ .name = "gta02-vibrator",
+ .num_resources = ARRAY_SIZE(gta02_vibrator_resources),
+ .resource = gta02_vibrator_resources,
+ .dev = {
+ .platform_data = >a02_vib_pdata,
+ },
+};
+#endif
+
+/* NOR Flash */
+
+#define GTA02_FLASH_BASE S3C2410_CS3 /* GCS3 */
+#define GTA02_FLASH_SIZE 0x200000 /* 2MBytes */
+
+static struct physmap_flash_data gta02_nor_flash_data = {
+ .width = 2,
+};
+
+static struct resource gta02_nor_flash_resource = {
+ .start = GTA02_FLASH_BASE,
+ .end = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device gta02_nor_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = >a02_nor_flash_data,
+ },
+ .resource = >a02_nor_flash_resource,
+ .num_resources = 1,
+};
+
+
+struct platform_device s3c24xx_pwm_device = {
+ .name = "s3c24xx_pwm",
+ .num_resources = 0,
+};
+
+static struct i2c_board_info gta02_i2c_devs[] __initdata = {
+ {
+ I2C_BOARD_INFO("pcf50633", 0x73),
+ .irq = GTA02_IRQ_PCF50633,
+ .platform_data = >a02_pcf_pdata,
+ },
+ {
+ I2C_BOARD_INFO("wm8753", 0x1a),
+ },
+};
+
+static struct s3c2410_nand_set gta02_nand_sets[] = {
+ [0] = {
+ .name = "neo1973-nand",
+ .nr_chips = 1,
+ .flags = S3C2410_NAND_BBT,
+ },
+};
+
+/* choose a set of timings derived from S3C@2442B MCP54
+ * data sheet (K5D2G13ACM-D075 MCP Memory)
+ */
+
+static struct s3c2410_platform_nand gta02_nand_info = {
+ .tacls = 0,
+ .twrph0 = 25,
+ .twrph1 = 15,
+ .nr_sets = ARRAY_SIZE(gta02_nand_sets),
+ .sets = gta02_nand_sets,
+ .software_ecc = 1,
+};
+
+
+static void gta02_s3c_mmc_set_power(unsigned char power_mode,
+ unsigned short vdd)
+{
+ static int is_on = -1;
+ int on;
+
+ on = power_mode == MMC_POWER_ON || power_mode == MMC_POWER_UP;
+ if (is_on != on)
+ gta02_wlan_reset(!on);
+ is_on = on;
+}
+
+
+static struct s3c24xx_mci_pdata gta02_s3c_mmc_cfg = {
+ .set_power = gta02_s3c_mmc_set_power,
+};
+
+static void gta02_udc_command(enum s3c2410_udc_cmd_e cmd)
+{
+ switch (cmd) {
+ case S3C2410_UDC_P_ENABLE:
+ printk(KERN_DEBUG "%s S3C2410_UDC_P_ENABLE\n", __func__);
+ gta02_gpb_setpin(GTA02_GPIO_USB_PULLUP, 1);
+ break;
+ case S3C2410_UDC_P_DISABLE:
+ printk(KERN_DEBUG "%s S3C2410_UDC_P_DISABLE\n", __func__);
+ gta02_gpb_setpin(GTA02_GPIO_USB_PULLUP, 0);
+ break;
+ case S3C2410_UDC_P_RESET:
+ printk(KERN_DEBUG "%s S3C2410_UDC_P_RESET\n", __func__);
+ /* FIXME! */
+ break;
+ default:
+ break;
+ }
+}
+
+/* get PMU to set USB current limit accordingly */
+
+static struct s3c2410_udc_mach_info gta02_udc_cfg = {
+ .vbus_draw = gta02_udc_vbus_draw,
+ .udc_command = gta02_udc_command,
+/* .get_vbus_status = gta02_udc_vbus_status,*/
+};
+
+
+/* Touchscreen configuration. */
+
+#ifdef CONFIG_TOUCHSCREEN_FILTER
+const static struct ts_filter_group_configuration gta02_ts_group = {
+ .length = 12,
+ .close_enough = 10,
+ .threshold = 6, /* At least half of the points in a group. */
+ .attempts = 10,
+};
+
+const static struct ts_filter_median_configuration gta02_ts_median = {
+ .extent = 20,
+ .decimation_below = 3,
+ .decimation_threshold = 8 * 3,
+ .decimation_above = 4,
+};
+
+const static struct ts_filter_mean_configuration gta02_ts_mean = {
+ .length = 4,
+};
+
+const static struct ts_filter_linear_configuration gta02_ts_linear = {
+ .constants = {1, 0, 0, 0, 1, 0, 1}, /* Don't modify coords. */
+ .coord0 = 0,
+ .coord1 = 1,
+};
+#endif
+
+const static struct ts_filter_chain_configuration gta02_filter_configuration[] =
+{
+#ifdef CONFIG_TOUCHSCREEN_FILTER
+ {&ts_filter_group_api, >a02_ts_group.config},
+ {&ts_filter_median_api, >a02_ts_median.config},
+ {&ts_filter_mean_api, >a02_ts_mean.config},
+ {&ts_filter_linear_api, >a02_ts_linear.config},
+#endif
+ {NULL, NULL},
+};
+
+const static struct s3c2410_ts_mach_info gta02_ts_cfg = {
+ .delay = 10000,
+ .presc = 0xff, /* slow as we can go */
+ .filter_config = gta02_filter_configuration,
+};
+
+
+
+static void gta02_bl_set_intensity(int intensity)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+ int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
+ int ret;
+
+ intensity >>= 2;
+
+ /*
+ * One code path that leads here is from a kernel panic. Trying to turn
+ * the backlight on just gives us a nearly endless stream of complaints
+ * and accomplishes nothing. We can't win. Just give up.
+ *
+ * In the unlikely event that there's another path leading here while
+ * we're atomic, we print at least a warning.
+ */
+ if (in_atomic()) {
+ printk(KERN_ERR
+ "gta02_bl_set_intensity called while atomic\n");
+ return;
+ }
+
+ if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
+ old_intensity = 0;
+ else
+ old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
+
+ if (intensity == old_intensity)
+ return;
+
+ /* We can't do this anywhere else */
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);
+
+ /*
+ * The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
+ * if seen, you have to re-enable the LED unit
+ */
+ if (!intensity || !old_intensity)
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);
+
+ if (!intensity) /* illegal to set LEDOUT to 0 */
+ ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
+ 2);
+ else
+ ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
+ intensity);
+
+ if (intensity)
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);
+
+}
+
+static struct generic_bl_info gta02_bl_info = {
+ .name = "gta02-bl",
+ .max_intensity = 0xff,
+ .default_intensity = 0xff,
+ .set_bl_intensity = gta02_bl_set_intensity,
+};
+
+static struct platform_device gta02_bl_dev = {
+ .name = "generic-bl",
+ .id = 1,
+ .dev = {
+ .platform_data = >a02_bl_info,
+ },
+};
+
+/* SPI: LCM control interface attached to Glamo3362 */
+
+static void gta02_jbt6k74_reset(int devidx, int level)
+{
+ glamo_lcm_reset(level);
+}
+
+static void gta02_jbt6k74_probe_completed(struct device *dev)
+{
+ struct pcf50633 *pcf = gta02_pcf;
+
+ /* Switch on backlight. Qi does not do it for us */
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDOUT, 0x01);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 0x01);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0x01);
+
+ gta02_bl_dev.dev.parent = dev;
+ platform_device_register(>a02_bl_dev);
+}
+
+const struct jbt6k74_platform_data jbt6k74_pdata = {
+ .reset = gta02_jbt6k74_reset,
+ .probe_completed = gta02_jbt6k74_probe_completed,
+};
+
+#if 0 /* currently this is not used and we use gpio spi */
+static struct glamo_spi_info glamo_spi_cfg = {
+ .board_size = ARRAY_SIZE(gta02_spi_board_info),
+ .board_info = gta02_spi_board_info,
+};
+#endif /* 0 */
+
+static struct glamo_spigpio_info glamo_spigpio_cfg = {
+ .pin_clk = GLAMO_GPIO10_OUTPUT,
+ .pin_mosi = GLAMO_GPIO11_OUTPUT,
+ .pin_cs = GLAMO_GPIO12_OUTPUT,
+ .pin_miso = 0,
+ .bus_num = 2,
+};
+
+/*----------- SPI: Accelerometers attached to SPI of s3c244x ----------------- */
+
+void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
+{
+ struct lis302dl_platform_data *pdata = lis->pdata;
+
+ if (!resume) {
+ /*
+ * we don't want to power them with a high level
+ * because GSENSOR_3V3 is not up during suspend
+ */
+ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
+ s3c2410_gpio_setpin(pdata->pin_mosi, 0);
+ /* misnomer: it is a pullDOWN in 2442 */
+ s3c2410_gpio_pullup(pdata->pin_miso, 1);
+ return;
+ }
+
+ /* back to normal */
+ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ /* misnomer: it is a pullDOWN in 2442 */
+ s3c2410_gpio_pullup(pdata->pin_miso, 0);
+
+ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT);
+
+}
+
+struct lis302dl_platform_data lis302_pdata_top = {
+ .name = "lis302-1 (top)",
+ .pin_chip_select= S3C2410_GPD12,
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
+ .interrupt = GTA02_IRQ_GSENSOR_1,
+ .open_drain = 1, /* altered at runtime by PCB rev */
+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
+};
+
+struct lis302dl_platform_data lis302_pdata_bottom = {
+ .name = "lis302-2 (bottom)",
+ .pin_chip_select= S3C2410_GPD13,
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
+ .interrupt = GTA02_IRQ_GSENSOR_2,
+ .open_drain = 1, /* altered at runtime by PCB rev */
+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
+};
+
+static struct spi_board_info gta02_spi_board_info[] = {
+ {
+ .modalias = "jbt6k74",
+ /* platform_data */
+ .platform_data = &jbt6k74_pdata,
+ /* controller_data */
+ /* irq */
+ .max_speed_hz = 100 * 1000,
+ .bus_num = 2,
+ /* chip_select */
+ },
+ {
+ .modalias = "lis302dl",
+ /* platform_data */
+ .platform_data = &lis302_pdata_top,
+ /* controller_data */
+ /* irq */
+ .max_speed_hz = 100 * 1000,
+ .bus_num = 3,
+ .chip_select = 0,
+ },
+
+ {
+ .modalias = "lis302dl",
+ /* platform_data */
+ .platform_data = &lis302_pdata_bottom,
+ /* controller_data */
+ /* irq */
+ .max_speed_hz = 100 * 1000,
+ .bus_num = 3,
+ .chip_select = 1,
+ },
+
+};
+
+static void gta02_lis302_chip_select(struct s3c2410_spigpio_info *info, int csid, int cs)
+{
+
+ /*
+ * Huh... "quirk"... CS on this device is not really "CS" like you can
+ * expect.
+ *
+ * When it is 0 it selects SPI interface mode.
+ * When it is 1 it selects I2C interface mode.
+ *
+ * Because we have 2 devices on one interface we have to make sure
+ * that the "disabled" device (actually in I2C mode) don't think we're
+ * talking to it.
+ *
+ * When we talk to the "enabled" device, the "disabled" device sees
+ * the clocks as I2C clocks, creating havoc.
+ *
+ * I2C sees MOSI going LOW while CLK HIGH as a START action, thus we
+ * must ensure this is never issued.
+ */
+
+ int cs_gpio, other_cs_gpio;
+
+ cs_gpio = csid ? S3C2410_GPD13 : S3C2410_GPD12;
+ other_cs_gpio = (1 - csid) ? S3C2410_GPD13 : S3C2410_GPD12;
+
+
+ if (cs == BITBANG_CS_ACTIVE) {
+ s3c2410_gpio_setpin(other_cs_gpio, 1);
+ s3c2410_gpio_setpin(cs_gpio, 1);
+ s3c2410_gpio_setpin(info->pin_clk, 1);
+ s3c2410_gpio_setpin(cs_gpio, 0);
+ } else {
+ s3c2410_gpio_setpin(cs_gpio, 1);
+ s3c2410_gpio_setpin(other_cs_gpio, 1);
+ }
+}
+
+static struct s3c2410_spigpio_info gta02_spigpio_cfg = {
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
+ .bus_num = 3,
+ .num_chipselect = 2,
+ .chip_select = gta02_lis302_chip_select,
+ .non_blocking_transfer = 1,
+};
+
+static struct platform_device gta02_spi_gpio_dev = {
+ .name = "spi_s3c24xx_gpio",
+ .dev = {
+ .platform_data = >a02_spigpio_cfg,
+ },
+};
+
+/*----------- / SPI: Accelerometers attached to SPI of s3c244x ----------------- */
+
+static struct resource gta02_led_resources[] = {
+ {
+ .name = "gta02-power:orange",
+ .start = GTA02_GPIO_PWR_LED1,
+ .end = GTA02_GPIO_PWR_LED1,
+ }, {
+ .name = "gta02-power:blue",
+ .start = GTA02_GPIO_PWR_LED2,
+ .end = GTA02_GPIO_PWR_LED2,
+ }, {
+ .name = "gta02-aux:red",
+ .start = GTA02_GPIO_AUX_LED,
+ .end = GTA02_GPIO_AUX_LED,
+ },
+};
+
+struct platform_device gta02_led_dev = {
+ .name = "gta02-led",
+ .num_resources = ARRAY_SIZE(gta02_led_resources),
+ .resource = gta02_led_resources,
+};
+
+static struct resource gta02_button_resources[] = {
+ [0] = {
+ .start = GTA02_GPIO_AUX_KEY,
+ .end = GTA02_GPIO_AUX_KEY,
+ },
+ [1] = {
+ .start = GTA02_GPIO_HOLD_KEY,
+ .end = GTA02_GPIO_HOLD_KEY,
+ },
+ [2] = {
+ .start = GTA02_GPIO_JACK_INSERT,
+ .end = GTA02_GPIO_JACK_INSERT,
+ },
+ [3] = {
+ .start = 0,
+ .end = 0,
+ },
+ [4] = {
+ .start = 0,
+ .end = 0,
+ },
+};
+
+static struct platform_device gta02_button_dev = {
+ .name = "gta02-button",
+ .num_resources = ARRAY_SIZE(gta02_button_resources),
+ .resource = gta02_button_resources,
+};
+
+static struct platform_device gta02_pm_usbhost_dev = {
+ .name = "gta02-pm-host",
+};
+
+
+/* USB */
+static struct s3c2410_hcd_info gta02_usb_info = {
+ .port[0] = {
+ .flags = S3C_HCDFLG_USED,
+ },
+ .port[1] = {
+ .flags = 0,
+ },
+};
+
+static int glamo_irq_is_wired(void)
+{
+ int rc;
+ int count = 0;
+
+ /*
+ * GTA02 S-Media IRQs prior to A5 are broken due to a lack of
+ * a pullup on the INT# line. Check for the bad behaviour.
+ */
+ s3c2410_gpio_setpin(S3C2410_GPG4, 0);
+ s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_OUTP);
+ s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_INP);
+ /*
+ * we force it low ourselves for a moment and resume being input.
+ * If there is a pullup, it won't stay low for long. But if the
+ * level converter is there as on < A5 revision, the weak keeper
+ * on the input of the LC will hold the line low indefinitiely
+ */
+ do
+ rc = s3c2410_gpio_getpin(S3C2410_GPG4);
+ while ((!rc) && ((count++) < 10));
+ if (rc) { /* it got pulled back up, it's good */
+ printk(KERN_INFO "Detected S-Media IRQ# pullup, "
+ "enabling interrupt\n");
+ return 0;
+ } else /* Gah we can't work with this level converter */
+ printk(KERN_WARNING "** Detected bad IRQ# circuit found"
+ " on pre-A5 GTA02: S-Media interrupt disabled **\n");
+ return -ENODEV;
+}
+
+static int gta02_glamo_can_set_mmc_power(void)
+{
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v3_SYSTEM_REV:
+ case GTA02v4_SYSTEM_REV:
+ case GTA02v5_SYSTEM_REV:
+ case GTA02v6_SYSTEM_REV:
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Smedia Glamo 3362 */
+
+/*
+ * we crank down SD Card clock dynamically when GPS is powered
+ */
+
+static int gta02_glamo_mci_use_slow(void)
+{
+ return gta02_pm_gps_is_on();
+}
+
+static void gta02_glamo_external_reset(int level)
+{
+ s3c2410_gpio_setpin(GTA02_GPIO_3D_RESET, level);
+ s3c2410_gpio_cfgpin(GTA02_GPIO_3D_RESET, S3C2410_GPIO_OUTPUT);
+}
+
+static struct glamofb_platform_data gta02_glamo_pdata = {
+ .width = 43,
+ .height = 58,
+ /* 24.5MHz --> 40.816ns */
+ .pixclock = 40816,
+ .left_margin = 8,
+ .right_margin = 16,
+ .upper_margin = 2,
+ .lower_margin = 16,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .fb_mem_size = 0x400000, /* glamo has 8 megs of SRAM. we use 4 */
+ .xres = {
+ .min = 240,
+ .max = 640,
+ .defval = 480,
+ },
+ .yres = {
+ .min = 320,
+ .max = 640,
+ .defval = 640,
+ },
+ .bpp = {
+ .min = 16,
+ .max = 16,
+ .defval = 16,
+ },
+ //.spi_info = &glamo_spi_cfg,
+ .spigpio_info = &glamo_spigpio_cfg,
+
+ /* glamo MMC function platform data */
+ .mmc_dev = >a02_mmc_dev,
+ .glamo_can_set_mci_power = gta02_glamo_can_set_mmc_power,
+ .glamo_mci_use_slow = gta02_glamo_mci_use_slow,
+ .glamo_irq_is_wired = glamo_irq_is_wired,
+ .glamo_external_reset = gta02_glamo_external_reset
+};
+
+static struct resource gta02_glamo_resources[] = {
+ [0] = {
+ .start = S3C2410_CS1,
+ .end = S3C2410_CS1 + 0x1000000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = GTA02_IRQ_3D,
+ .end = GTA02_IRQ_3D,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = GTA02_GPIO_3D_RESET,
+ .end = GTA02_GPIO_3D_RESET,
+ },
+};
+
+static struct platform_device gta02_glamo_dev = {
+ .name = "glamo3362",
+ .num_resources = ARRAY_SIZE(gta02_glamo_resources),
+ .resource = gta02_glamo_resources,
+ .dev = {
+ .platform_data = >a02_glamo_pdata,
+ },
+};
+
+static void mangle_glamo_res_by_system_rev(void)
+{
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v1_SYSTEM_REV:
+ break;
+ default:
+ gta02_glamo_resources[2].start = GTA02_GPIO_3D_RESET;
+ gta02_glamo_resources[2].end = GTA02_GPIO_3D_RESET;
+ break;
+ }
+
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v1_SYSTEM_REV:
+ case GTA02v2_SYSTEM_REV:
+ case GTA02v3_SYSTEM_REV:
+ /* case GTA02v4_SYSTEM_REV: - FIXME: handle this later */
+ /* The hardware is missing a pull-up resistor and thus can't
+ * support the Smedia Glamo IRQ */
+ gta02_glamo_resources[1].start = 0;
+ gta02_glamo_resources[1].end = 0;
+ break;
+ }
+}
+
+static void __init gta02_map_io(void)
+{
+ s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
+ s3c24xx_init_clocks(12000000);
+ s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
+}
+
+static irqreturn_t gta02_modem_irq(int irq, void *param)
+{
+/* printk(KERN_DEBUG "modem wakeup interrupt\n");*/
+ gta_gsm_interrupts++;
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ar6000_wow_irq(int irq, void *param)
+{
+/* printk(KERN_DEBUG "ar6000_wow interrupt\n");*/
+ return IRQ_HANDLED;
+}
+
+/*
+ * hardware_ecc=1|0
+ */
+static char hardware_ecc_str[4] __initdata = "";
+
+static int __init hardware_ecc_setup(char *str)
+{
+ if (str)
+ strlcpy(hardware_ecc_str, str, sizeof(hardware_ecc_str));
+ return 1;
+}
+
+__setup("hardware_ecc=", hardware_ecc_setup);
+
+/* these are the guys that don't need to be children of PMU */
+
+static struct platform_device *gta02_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_wdt,
+ &s3c_device_sdi,
+ &s3c_device_usbgadget,
+ &s3c_device_nand,
+ >a02_nor_flash,
+
+ &s3c24xx_pwm_device,
+ >a02_led_dev,
+ >a02_pm_wlan_dev, /* not dependent on PMU */
+
+ &s3c_device_iis,
+ &s3c_device_i2c0,
+};
+
+/* these guys DO need to be children of PMU */
+
+static struct platform_device *gta02_devices_pmu_children[] = {
+ &s3c_device_ts, /* input 1 */
+ >a02_pm_gsm_dev,
+ >a02_pm_usbhost_dev,
+ >a02_spi_gpio_dev, /* input 2 and 3 */
+ >a02_button_dev, /* input 4 */
+ >a02_resume_reason_device,
+};
+
+static void gta02_pmu_regulator_registered(struct pcf50633 *pcf, int id)
+{
+ struct platform_device *regulator, *pdev;
+
+ gta02_pcf = pcf;
+
+ regulator = pcf->regulator_pdev[id];
+
+ switch(id) {
+ case PCF50633_REGULATOR_LDO4:
+ pdev = >a02_pm_bt_dev;
+ break;
+ case PCF50633_REGULATOR_LDO5:
+ pdev = >a02_pm_gps_dev;
+ break;
+ case PCF50633_REGULATOR_HCLDO:
+ pdev = >a02_glamo_dev;
+ break;
+ default:
+ return;
+ }
+
+ pdev->dev.parent = ®ulator->dev;
+ platform_device_register(pdev);
+}
+
+/* this is called when pc50633 is probed, unfortunately quite late in the
+ * day since it is an I2C bus device. Here we can belatedly define some
+ * platform devices with the advantage that we can mark the pcf50633 as the
+ * parent. This makes them get suspended and resumed with their parent
+ * the pcf50633 still around.
+ */
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
+{
+ int n;
+
+ for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
+ gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
+
+ mangle_glamo_res_by_system_rev();
+ platform_add_devices(gta02_devices_pmu_children,
+ ARRAY_SIZE(gta02_devices_pmu_children));
+
+/* regulator_has_full_constraints();*/
+}
+
+static void gta02_poweroff(void)
+{
+ pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN,
+ PCF50633_OOCSHDWN_GOSTDBY, PCF50633_OOCSHDWN_GOSTDBY);
+}
+
+static void __init gta02_machine_init(void)
+{
+ int rc;
+
+ /* set the panic callback to make AUX blink fast */
+ panic_blink = gta02_panic_blink;
+
+ switch (S3C_SYSTEM_REV_ATAG) {
+ case GTA02v6_SYSTEM_REV:
+ /* we need push-pull interrupt from motion sensors */
+ lis302_pdata_top.open_drain = 0;
+ lis302_pdata_bottom.open_drain = 0;
+ break;
+ default:
+ break;
+ }
+
+ spin_lock_init(&motion_irq_lock);
+
+#ifdef CONFIG_CHARGER_PCF50633
+ INIT_DELAYED_WORK(>a02_charger_work, gta02_charger_worker);
+#endif
+
+ /* Glamo chip select optimization */
+/* *((u32 *)(S3C2410_MEMREG(((1 + 1) << 2)))) = 0x1280; */
+
+ /* do not force soft ecc if we are asked to use hardware_ecc */
+ if (hardware_ecc_str[0] == '1')
+ gta02_nand_info.software_ecc = 0;
+
+ s3c_device_usb.dev.platform_data = >a02_usb_info;
+ s3c_device_nand.dev.platform_data = >a02_nand_info;
+ s3c_device_sdi.dev.platform_data = >a02_s3c_mmc_cfg;
+
+ /* acc sensor chip selects */
+ s3c2410_gpio_setpin(S3C2410_GPD12, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPD12, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_setpin(S3C2410_GPD13, 1);
+ s3c2410_gpio_cfgpin(S3C2410_GPD13, S3C2410_GPIO_OUTPUT);
+
+ s3c24xx_udc_set_platdata(>a02_udc_cfg);
+ s3c_i2c0_set_platdata(NULL);
+ set_s3c2410ts_info(>a02_ts_cfg);
+
+ mangle_glamo_res_by_system_rev();
+
+ i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
+ spi_register_board_info(gta02_spi_board_info,
+ ARRAY_SIZE(gta02_spi_board_info));
+
+#ifdef CONFIG_CHARGER_PCF50633
+ mangle_pmu_pdata_by_system_rev();
+#endif
+
+ platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
+
+ s3c_pm_init();
+
+ /* Make sure the modem can wake us up */
+ set_irq_type(GTA02_IRQ_MODEM, IRQ_TYPE_EDGE_RISING);
+ rc = request_irq(GTA02_IRQ_MODEM, gta02_modem_irq, IRQF_DISABLED,
+ "modem", NULL);
+ if (rc < 0)
+ printk(KERN_ERR "GTA02: can't request GSM modem wakeup IRQ\n");
+ enable_irq_wake(GTA02_IRQ_MODEM);
+
+ /* Make sure the wifi module can wake us up*/
+ set_irq_type(GTA02_IRQ_WLAN_GPIO1, IRQ_TYPE_EDGE_RISING);
+ rc = request_irq(GTA02_IRQ_WLAN_GPIO1, ar6000_wow_irq, IRQF_DISABLED,
+ "ar6000", NULL);
+
+ if (rc < 0)
+ printk(KERN_ERR "GTA02: can't request ar6k wakeup IRQ\n");
+ enable_irq_wake(GTA02_IRQ_WLAN_GPIO1);
+
+ pm_power_off = gta02_poweroff;
+
+ /* Register the HDQ and vibrator as children of pwm device */
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+ gta02_hdq_device.dev.parent = &s3c24xx_pwm_device.dev;
+ platform_device_register(>a02_hdq_device);
+#endif
+#ifdef CONFIG_LEDS_GTA02_VIBRATOR
+ gta02_vibrator_dev.dev.parent = &s3c24xx_pwm_device.dev;
+ platform_device_register(>a02_vibrator_dev);
+#endif
+}
+
+void DEBUG_LED(int n)
+{
+ switch (n) {
+ case 0:
+ gta02_gpb_setpin(GTA02_GPIO_PWR_LED1, 1);
+ break;
+ case 1:
+ gta02_gpb_setpin(GTA02_GPIO_PWR_LED2, 1);
+ break;
+ default:
+ gta02_gpb_setpin(GTA02_GPIO_AUX_LED, 1);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(DEBUG_LED);
+
+MACHINE_START(NEO1973_GTA02, "GTA02")
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = gta02_map_io,
+ .init_irq = s3c24xx_init_irq,
+ .init_machine = gta02_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
--- /dev/null
+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.
--- /dev/null
+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
+
+
--- /dev/null
+/*
+ *
+ * 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.
+ *
+ *
+ *
+ */
+
+/*
+ * This driver is a pseudo ethernet driver to access the Atheros AR6000
+ * WLAN Device
+ */
+static const char athId[] __attribute__ ((unused)) = "$Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/ar6000_drv.c#2 $";
+
+#include "ar6000_drv.h"
+#include "htc.h"
+
+MODULE_LICENSE("GPL and additional rights");
+
+#ifndef REORG_APTC_HEURISTICS
+#undef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+#endif /* REORG_APTC_HEURISTICS */
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+#define APTC_TRAFFIC_SAMPLING_INTERVAL 100 /* msec */
+#define APTC_UPPER_THROUGHPUT_THRESHOLD 3000 /* Kbps */
+#define APTC_LOWER_THROUGHPUT_THRESHOLD 2000 /* Kbps */
+
+typedef struct aptc_traffic_record {
+ A_BOOL timerScheduled;
+ struct timeval samplingTS;
+ unsigned long bytesReceived;
+ unsigned long bytesTransmitted;
+} APTC_TRAFFIC_RECORD;
+
+A_TIMER aptcTimer;
+APTC_TRAFFIC_RECORD aptcTR;
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+int bmienable = 0;
+unsigned int bypasswmi = 0;
+unsigned int debuglevel = 0;
+int tspecCompliance = 1;
+unsigned int busspeedlow = 0;
+unsigned int onebitmode = 0;
+unsigned int skipflash = 0;
+unsigned int wmitimeout = 2;
+unsigned int wlanNodeCaching = 1;
+unsigned int enableuartprint = 0;
+unsigned int logWmiRawMsgs = 0;
+unsigned int enabletimerwar = 0;
+unsigned int mbox_yield_limit = 99;
+int reduce_credit_dribble = 1 + HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF;
+int allow_trace_signal = 0;
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+unsigned int testmode =0;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+module_param(bmienable, int, 0644);
+module_param(bypasswmi, int, 0644);
+module_param(debuglevel, int, 0644);
+module_param(tspecCompliance, int, 0644);
+module_param(onebitmode, int, 0644);
+module_param(busspeedlow, int, 0644);
+module_param(skipflash, int, 0644);
+module_param(wmitimeout, int, 0644);
+module_param(wlanNodeCaching, int, 0644);
+module_param(logWmiRawMsgs, int, 0644);
+module_param(enableuartprint, int, 0644);
+module_param(enabletimerwar, int, 0644);
+module_param(mbox_yield_limit, int, 0644);
+module_param(reduce_credit_dribble, int, 0644);
+module_param(allow_trace_signal, int, 0644);
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+module_param(testmode, int, 0644);
+#endif
+#else
+
+#define __user
+/* for linux 2.4 and lower */
+MODULE_PARM(bmienable,"i");
+MODULE_PARM(bypasswmi,"i");
+MODULE_PARM(debuglevel, "i");
+MODULE_PARM(onebitmode,"i");
+MODULE_PARM(busspeedlow, "i");
+MODULE_PARM(skipflash, "i");
+MODULE_PARM(wmitimeout, "i");
+MODULE_PARM(wlanNodeCaching, "i");
+MODULE_PARM(enableuartprint,"i");
+MODULE_PARM(logWmiRawMsgs, "i");
+MODULE_PARM(enabletimerwar,"i");
+MODULE_PARM(mbox_yield_limit,"i");
+MODULE_PARM(reduce_credit_dribble,"i");
+MODULE_PARM(allow_trace_signal,"i");
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+MODULE_PARM(testmode, "i");
+#endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
+/* in 2.6.10 and later this is now a pointer to a uint */
+unsigned int _mboxnum = HTC_MAILBOX_NUM_MAX;
+#define mboxnum &_mboxnum
+#else
+unsigned int mboxnum = HTC_MAILBOX_NUM_MAX;
+#endif
+
+#ifdef CONFIG_AR6000_WLAN_RESET
+unsigned int resetok = 1;
+#else
+unsigned int resetok = 0;
+#endif
+
+#ifdef DEBUG
+A_UINT32 g_dbg_flags = DBG_DEFAULTS;
+unsigned int debugflags = 0;
+int debugdriver = 1;
+unsigned int debughtc = 128;
+unsigned int debugbmi = 1;
+unsigned int debughif = 2;
+unsigned int txcreditsavailable[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int txcreditsconsumed[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int txcreditintrenable[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int txcreditintrenableaggregate[HTC_MAILBOX_NUM_MAX] = {0};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+module_param(debugflags, int, 0644);
+module_param(debugdriver, int, 0644);
+module_param(debughtc, int, 0644);
+module_param(debugbmi, int, 0644);
+module_param(debughif, int, 0644);
+module_param(resetok, int, 0644);
+module_param_array(txcreditsavailable, int, mboxnum, 0644);
+module_param_array(txcreditsconsumed, int, mboxnum, 0644);
+module_param_array(txcreditintrenable, int, mboxnum, 0644);
+module_param_array(txcreditintrenableaggregate, int, mboxnum, 0644);
+#else
+/* linux 2.4 and lower */
+MODULE_PARM(debugflags,"i");
+MODULE_PARM(debugdriver, "i");
+MODULE_PARM(debughtc, "i");
+MODULE_PARM(debugbmi, "i");
+MODULE_PARM(debughif, "i");
+MODULE_PARM(resetok, "i");
+MODULE_PARM(txcreditsavailable, "0-3i");
+MODULE_PARM(txcreditsconsumed, "0-3i");
+MODULE_PARM(txcreditintrenable, "0-3i");
+MODULE_PARM(txcreditintrenableaggregate, "0-3i");
+#endif
+
+#endif /* DEBUG */
+
+unsigned int tx_attempt[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int tx_post[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int tx_complete[HTC_MAILBOX_NUM_MAX] = {0};
+unsigned int hifBusRequestNumMax = 40;
+unsigned int war23838_disabled = 0;
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+unsigned int enableAPTCHeuristics = 1;
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+module_param_array(tx_attempt, int, mboxnum, 0644);
+module_param_array(tx_post, int, mboxnum, 0644);
+module_param_array(tx_complete, int, mboxnum, 0644);
+module_param(hifBusRequestNumMax, int, 0644);
+module_param(war23838_disabled, int, 0644);
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+module_param(enableAPTCHeuristics, int, 0644);
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+#else
+MODULE_PARM(tx_attempt, "0-3i");
+MODULE_PARM(tx_post, "0-3i");
+MODULE_PARM(tx_complete, "0-3i");
+MODULE_PARM(hifBusRequestNumMax, "i");
+MODULE_PARM(war23838_disabled, "i");
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+MODULE_PARM(enableAPTCHeuristics, "i");
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+#endif
+
+#ifdef BLOCK_TX_PATH_FLAG
+int blocktx = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+module_param(blocktx, int, 0644);
+#else
+MODULE_PARM(blocktx, "i");
+#endif
+#endif /* BLOCK_TX_PATH_FLAG */
+
+// TODO move to arsoft_c
+USER_RSSI_THOLD rssi_map[12];
+
+int reconnect_flag = 0;
+
+DECLARE_WAIT_QUEUE_HEAD(ar6000_scan_queue);
+
+/* Function declarations */
+static int ar6000_init_module(void);
+static void ar6000_cleanup_module(void);
+
+int ar6000_init(struct net_device *dev);
+static int ar6000_open(struct net_device *dev);
+static int ar6000_close(struct net_device *dev);
+static void ar6000_init_control_info(AR_SOFTC_T *ar);
+static int ar6000_data_tx(struct sk_buff *skb, struct net_device *dev);
+
+static void ar6000_destroy(struct net_device *dev, unsigned int unregister);
+static void ar6000_detect_error(unsigned long ptr);
+static struct net_device_stats *ar6000_get_stats(struct net_device *dev);
+static struct iw_statistics *ar6000_get_iwstats(struct net_device * dev);
+
+/*
+ * HTC service connection handlers
+ */
+static void ar6000_avail_ev(HTC_HANDLE HTCHandle);
+
+static void ar6000_unavail_ev(void *Instance);
+
+static void ar6000_target_failure(void *Instance, A_STATUS Status);
+
+static void ar6000_rx(void *Context, HTC_PACKET *pPacket);
+
+static void ar6000_rx_refill(void *Context,HTC_ENDPOINT_ID Endpoint);
+
+static void ar6000_tx_complete(void *Context, HTC_PACKET *pPacket);
+
+static void ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint);
+
+static void ar6000_tx_queue_avail(void *Context, HTC_ENDPOINT_ID Endpoint);
+
+/*
+ * Static variables
+ */
+
+static struct net_device *ar6000_devices[MAX_AR6000];
+extern struct iw_handler_def ath_iw_handler_def;
+DECLARE_WAIT_QUEUE_HEAD(arEvent);
+static void ar6000_cookie_init(AR_SOFTC_T *ar);
+static void ar6000_cookie_cleanup(AR_SOFTC_T *ar);
+static void ar6000_free_cookie(AR_SOFTC_T *ar, struct ar_cookie * cookie);
+static struct ar_cookie *ar6000_alloc_cookie(AR_SOFTC_T *ar);
+static void ar6000_TxDataCleanup(AR_SOFTC_T *ar);
+
+#ifdef USER_KEYS
+static A_STATUS ar6000_reinstall_keys(AR_SOFTC_T *ar,A_UINT8 key_op_ctrl);
+#endif
+
+
+static struct ar_cookie s_ar_cookie_mem[MAX_COOKIE_NUM];
+
+#define HOST_INTEREST_ITEM_ADDRESS(ar, item) \
+((ar->arTargetType == TARGET_TYPE_AR6001) ? \
+ AR6001_HOST_INTEREST_ITEM_ADDRESS(item) : \
+ AR6002_HOST_INTEREST_ITEM_ADDRESS(item))
+
+
+/* Debug log support */
+
+/*
+ * Flag to govern whether the debug logs should be parsed in the kernel
+ * or reported to the application.
+ */
+#ifdef DEBUG
+#define REPORT_DEBUG_LOGS_TO_APP
+#endif
+
+A_STATUS
+ar6000_set_host_app_area(AR_SOFTC_T *ar)
+{
+ A_UINT32 address, data;
+ struct host_app_area_s host_app_area;
+
+ /* Fetch the address of the host_app_area_s instance in the host interest area */
+ address = HOST_INTEREST_ITEM_ADDRESS(ar, hi_app_host_interest);
+ if (ar6000_ReadRegDiag(ar->arHifDevice, &address, &data) != A_OK) {
+ return A_ERROR;
+ }
+ address = data;
+ host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION;
+ if (ar6000_WriteDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)&host_app_area,
+ sizeof(struct host_app_area_s)) != A_OK)
+ {
+ return A_ERROR;
+ }
+
+ return A_OK;
+}
+
+A_UINT32
+dbglog_get_debug_hdr_ptr(AR_SOFTC_T *ar)
+{
+ A_UINT32 param;
+ A_UINT32 address;
+ A_STATUS status;
+
+ address = HOST_INTEREST_ITEM_ADDRESS(ar, hi_dbglog_hdr);
+ if ((status = ar6000_ReadDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)¶m, 4)) != A_OK)
+ {
+ param = 0;
+ }
+
+ return param;
+}
+
+/*
+ * The dbglog module has been initialized. Its ok to access the relevant
+ * data stuctures over the diagnostic window.
+ */
+void
+ar6000_dbglog_init_done(AR_SOFTC_T *ar)
+{
+ ar->dbglog_init_done = TRUE;
+}
+
+A_UINT32
+dbglog_get_debug_fragment(A_INT8 *datap, A_UINT32 len, A_UINT32 limit)
+{
+ A_INT32 *buffer;
+ A_UINT32 count;
+ A_UINT32 numargs;
+ A_UINT32 length;
+ A_UINT32 fraglen;
+
+ count = fraglen = 0;
+ buffer = (A_INT32 *)datap;
+ length = (limit >> 2);
+
+ if (len <= limit) {
+ fraglen = len;
+ } else {
+ while (count < length) {
+ numargs = DBGLOG_GET_NUMARGS(buffer[count]);
+ fraglen = (count << 2);
+ count += numargs + 1;
+ }
+ }
+
+ return fraglen;
+}
+
+void
+dbglog_parse_debug_logs(A_INT8 *datap, A_UINT32 len)
+{
+ A_INT32 *buffer;
+ A_UINT32 count;
+ A_UINT32 timestamp;
+ A_UINT32 debugid;
+ A_UINT32 moduleid;
+ A_UINT32 numargs;
+ A_UINT32 length;
+
+ count = 0;
+ buffer = (A_INT32 *)datap;
+ length = (len >> 2);
+ while (count < length) {
+ debugid = DBGLOG_GET_DBGID(buffer[count]);
+ moduleid = DBGLOG_GET_MODULEID(buffer[count]);
+ numargs = DBGLOG_GET_NUMARGS(buffer[count]);
+ timestamp = DBGLOG_GET_TIMESTAMP(buffer[count]);
+ switch (numargs) {
+ case 0:
+ AR_DEBUG_PRINTF("%d %d (%d)\n", moduleid, debugid, timestamp);
+ break;
+
+ case 1:
+ AR_DEBUG_PRINTF("%d %d (%d): 0x%x\n", moduleid, debugid,
+ timestamp, buffer[count+1]);
+ break;
+
+ case 2:
+ AR_DEBUG_PRINTF("%d %d (%d): 0x%x, 0x%x\n", moduleid, debugid,
+ timestamp, buffer[count+1], buffer[count+2]);
+ break;
+
+ default:
+ AR_DEBUG_PRINTF("Invalid args: %d\n", numargs);
+ }
+ count += numargs + 1;
+ }
+}
+
+int
+ar6000_dbglog_get_debug_logs(AR_SOFTC_T *ar)
+{
+ struct dbglog_hdr_s debug_hdr;
+ struct dbglog_buf_s debug_buf;
+ A_UINT32 address;
+ A_UINT32 length;
+ A_UINT32 dropped;
+ A_UINT32 firstbuf;
+ A_UINT32 debug_hdr_ptr;
+
+ if (!ar->dbglog_init_done) return A_ERROR;
+
+#ifndef CONFIG_AR6000_WLAN_DEBUG
+ return 0;
+#endif
+
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ if (ar->dbgLogFetchInProgress) {
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ return A_EBUSY;
+ }
+
+ /* block out others */
+ ar->dbgLogFetchInProgress = TRUE;
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ debug_hdr_ptr = dbglog_get_debug_hdr_ptr(ar);
+ printk("debug_hdr_ptr: 0x%x\n", debug_hdr_ptr);
+
+ /* Get the contents of the ring buffer */
+ if (debug_hdr_ptr) {
+ address = debug_hdr_ptr;
+ length = sizeof(struct dbglog_hdr_s);
+ ar6000_ReadDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)&debug_hdr, length);
+ address = (A_UINT32)debug_hdr.dbuf;
+ firstbuf = address;
+ dropped = debug_hdr.dropped;
+ length = sizeof(struct dbglog_buf_s);
+ ar6000_ReadDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)&debug_buf, length);
+
+ do {
+ address = (A_UINT32)debug_buf.buffer;
+ length = debug_buf.length;
+ if ((length) && (debug_buf.length <= debug_buf.bufsize)) {
+ /* Rewind the index if it is about to overrun the buffer */
+ if (ar->log_cnt > (DBGLOG_HOST_LOG_BUFFER_SIZE - length)) {
+ ar->log_cnt = 0;
+ }
+ if(A_OK != ar6000_ReadDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)&ar->log_buffer[ar->log_cnt], length))
+ {
+ break;
+ }
+ ar6000_dbglog_event(ar, dropped, &ar->log_buffer[ar->log_cnt], length);
+ ar->log_cnt += length;
+ } else {
+ AR_DEBUG_PRINTF("Length: %d (Total size: %d)\n",
+ debug_buf.length, debug_buf.bufsize);
+ }
+
+ address = (A_UINT32)debug_buf.next;
+ length = sizeof(struct dbglog_buf_s);
+ if(A_OK != ar6000_ReadDataDiag(ar->arHifDevice, address,
+ (A_UCHAR *)&debug_buf, length))
+ {
+ break;
+ }
+
+ } while (address != firstbuf);
+ }
+
+ ar->dbgLogFetchInProgress = FALSE;
+
+ return A_OK;
+}
+
+void
+ar6000_dbglog_event(AR_SOFTC_T *ar, A_UINT32 dropped,
+ A_INT8 *buffer, A_UINT32 length)
+{
+#ifdef REPORT_DEBUG_LOGS_TO_APP
+ #define MAX_WIRELESS_EVENT_SIZE 252
+ /*
+ * Break it up into chunks of MAX_WIRELESS_EVENT_SIZE bytes of messages.
+ * There seems to be a limitation on the length of message that could be
+ * transmitted to the user app via this mechanism.
+ */
+ A_UINT32 send, sent;
+
+ sent = 0;
+ send = dbglog_get_debug_fragment(&buffer[sent], length - sent,
+ MAX_WIRELESS_EVENT_SIZE);
+ while (send) {
+ ar6000_send_event_to_app(ar, WMIX_DBGLOG_EVENTID, &buffer[sent], send);
+ sent += send;
+ send = dbglog_get_debug_fragment(&buffer[sent], length - sent,
+ MAX_WIRELESS_EVENT_SIZE);
+ }
+#else
+ AR_DEBUG_PRINTF("Dropped logs: 0x%x\nDebug info length: %d\n",
+ dropped, length);
+
+ /* Interpret the debug logs */
+ dbglog_parse_debug_logs(buffer, length);
+#endif /* REPORT_DEBUG_LOGS_TO_APP */
+}
+
+
+
+static int __init
+ar6000_init_module(void)
+{
+ static int probed = 0;
+ A_STATUS status;
+ HTC_INIT_INFO initInfo;
+
+ A_MEMZERO(&initInfo,sizeof(initInfo));
+ initInfo.AddInstance = ar6000_avail_ev;
+ initInfo.DeleteInstance = ar6000_unavail_ev;
+ initInfo.TargetFailure = ar6000_target_failure;
+
+
+#ifdef DEBUG
+ /* Set the debug flags if specified at load time */
+ if(debugflags != 0)
+ {
+ g_dbg_flags = debugflags;
+ }
+#endif
+
+ if (probed) {
+ return -ENODEV;
+ }
+ probed++;
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+ memset(&aptcTR, 0, sizeof(APTC_TRAFFIC_RECORD));
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+#ifdef CONFIG_HOST_GPIO_SUPPORT
+ ar6000_gpio_init();
+#endif /* CONFIG_HOST_GPIO_SUPPORT */
+
+ status = HTCInit(&initInfo);
+ if(status != A_OK)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit
+ar6000_cleanup_module(void)
+{
+ int i = 0;
+ struct net_device *ar6000_netdev;
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+ /* Delete the Adaptive Power Control timer */
+ if (timer_pending(&aptcTimer)) {
+ del_timer_sync(&aptcTimer);
+ }
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+ for (i=0; i < MAX_AR6000; i++) {
+ if (ar6000_devices[i] != NULL) {
+ ar6000_netdev = ar6000_devices[i];
+ ar6000_devices[i] = NULL;
+ ar6000_destroy(ar6000_netdev, 1);
+ }
+ }
+
+ /* shutting down HTC will cause the HIF layer to detach from the
+ * underlying bus driver which will cause the subsequent deletion of
+ * all HIF and HTC instances */
+ HTCShutDown();
+
+ AR_DEBUG_PRINTF("ar6000_cleanup: success\n");
+}
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+void
+aptcTimerHandler(unsigned long arg)
+{
+ A_UINT32 numbytes;
+ A_UINT32 throughput;
+ AR_SOFTC_T *ar;
+ A_STATUS status;
+
+ ar = (AR_SOFTC_T *)arg;
+ A_ASSERT(ar != NULL);
+ A_ASSERT(!timer_pending(&aptcTimer));
+
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ /* Get the number of bytes transferred */
+ numbytes = aptcTR.bytesTransmitted + aptcTR.bytesReceived;
+ aptcTR.bytesTransmitted = aptcTR.bytesReceived = 0;
+
+ /* Calculate and decide based on throughput thresholds */
+ throughput = ((numbytes * 8)/APTC_TRAFFIC_SAMPLING_INTERVAL); /* Kbps */
+ if (throughput < APTC_LOWER_THROUGHPUT_THRESHOLD) {
+ /* Enable Sleep and delete the timer */
+ A_ASSERT(ar->arWmiReady == TRUE);
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ status = wmi_powermode_cmd(ar->arWmi, REC_POWER);
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ A_ASSERT(status == A_OK);
+ aptcTR.timerScheduled = FALSE;
+ } else {
+ A_TIMEOUT_MS(&aptcTimer, APTC_TRAFFIC_SAMPLING_INTERVAL, 0);
+ }
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+}
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+
+
+/* set HTC block size, assume BMI is already initialized */
+A_STATUS ar6000_SetHTCBlockSize(AR_SOFTC_T *ar)
+{
+ A_STATUS status;
+ A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX];
+
+ do {
+ /* get the block sizes */
+ status = HIFConfigureDevice(ar->arHifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
+ blocksizes, sizeof(blocksizes));
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF("Failed to get block size info from HIF layer...\n");
+ break;
+ }
+ /* note: we actually get the block size for mailbox 1, for SDIO the block
+ * size on mailbox 0 is artificially set to 1 */
+ /* must be a power of 2 */
+ A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0);
+
+ /* set the host interest area for the block size */
+ status = BMIWriteMemory(ar->arHifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(ar, hi_mbox_io_block_sz),
+ (A_UCHAR *)&blocksizes[1],
+ 4);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF("BMIWriteMemory for IO block size failed \n");
+ break;
+ }
+
+ AR_DEBUG_PRINTF("Block Size Set: %d (target address:0x%X)\n",
+ blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(ar, hi_mbox_io_block_sz));
+
+ /* set the host interest area for the mbox ISR yield limit */
+ status = BMIWriteMemory(ar->arHifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(ar, hi_mbox_isr_yield_limit),
+ (A_UCHAR *)&mbox_yield_limit,
+ 4);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF("BMIWriteMemory for yield limit failed \n");
+ break;
+ }
+
+ } while (FALSE);
+
+ return status;
+}
+
+static void free_raw_buffers(AR_SOFTC_T *ar)
+{
+ int i, j;
+
+ for (i = 0; i != HTC_RAW_STREAM_NUM_MAX; i++) {
+ for (j = 0; j != RAW_HTC_READ_BUFFERS_NUM; j++)
+ kfree(ar->raw_htc_read_buffer[i][j]);
+ for (j = 0; j != RAW_HTC_WRITE_BUFFERS_NUM; j++)
+ kfree(ar->raw_htc_write_buffer[i][j]);
+ }
+}
+
+static int alloc_raw_buffers(AR_SOFTC_T *ar)
+{
+ int i, j;
+ raw_htc_buffer *b;
+
+ for (i = 0; i != HTC_RAW_STREAM_NUM_MAX; i++) {
+ for (j = 0; j != RAW_HTC_READ_BUFFERS_NUM; j++) {
+ b = kzalloc(sizeof(*b), GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+ ar->raw_htc_read_buffer[i][j] = b;
+ }
+ for (j = 0; j != RAW_HTC_WRITE_BUFFERS_NUM; j++) {
+ b = kzalloc(sizeof(*b), GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+ ar->raw_htc_write_buffer[i][j] = b;
+ }
+ }
+ return 0;
+}
+
+/*
+ * HTC Event handlers
+ */
+static void
+ar6000_avail_ev(HTC_HANDLE HTCHandle)
+{
+ int i;
+ struct net_device *dev;
+ AR_SOFTC_T *ar;
+ int device_index = 0;
+
+ AR_DEBUG_PRINTF("ar6000_available\n");
+
+ for (i=0; i < MAX_AR6000; i++) {
+ if (ar6000_devices[i] == NULL) {
+ break;
+ }
+ }
+
+ if (i == MAX_AR6000) {
+ AR_DEBUG_PRINTF("ar6000_available: max devices reached\n");
+ return;
+ }
+
+ /* Save this. It gives a bit better readability especially since */
+ /* we use another local "i" variable below. */
+ device_index = i;
+
+ A_ASSERT(HTCHandle != NULL);
+
+ dev = alloc_etherdev(sizeof(AR_SOFTC_T));
+ if (dev == NULL) {
+ AR_DEBUG_PRINTF("ar6000_available: can't alloc etherdev\n");
+ return;
+ }
+
+ ether_setup(dev);
+
+ if (netdev_priv(dev) == NULL) {
+ printk(KERN_CRIT "ar6000_available: Could not allocate memory\n");
+ return;
+ }
+
+ A_MEMZERO(netdev_priv(dev), sizeof(AR_SOFTC_T));
+
+ ar = (AR_SOFTC_T *)netdev_priv(dev);
+ ar->arNetDev = dev;
+ ar->arHtcTarget = HTCHandle;
+ ar->arHifDevice = HTCGetHifDevice(HTCHandle);
+ ar->arWlanState = WLAN_ENABLED;
+ ar->arRadioSwitch = WLAN_ENABLED;
+ ar->arDeviceIndex = device_index;
+
+ A_INIT_TIMER(&ar->arHBChallengeResp.timer, ar6000_detect_error, dev);
+ ar->arHBChallengeResp.seqNum = 0;
+ ar->arHBChallengeResp.outstanding = FALSE;
+ ar->arHBChallengeResp.missCnt = 0;
+ ar->arHBChallengeResp.frequency = AR6000_HB_CHALLENGE_RESP_FREQ_DEFAULT;
+ ar->arHBChallengeResp.missThres = AR6000_HB_CHALLENGE_RESP_MISS_THRES_DEFAULT;
+
+ ar6000_init_control_info(ar);
+ init_waitqueue_head(&arEvent);
+ sema_init(&ar->arSem, 1);
+
+ if (alloc_raw_buffers(ar)) {
+ free_raw_buffers(ar);
+ /*
+ * @@@ Clean up our own mess, but for anything else, cheerfully mimick
+ * the beautiful error non-handling of the rest of this function.
+ */
+ return;
+ }
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+ A_INIT_TIMER(&aptcTimer, aptcTimerHandler, ar);
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+ /*
+ * If requested, perform some magic which requires no cooperation from
+ * the Target. It causes the Target to ignore flash and execute to the
+ * OS from ROM.
+ *
+ * This is intended to support recovery from a corrupted flash on Targets
+ * that support flash.
+ */
+ if (skipflash)
+ {
+ ar6000_reset_device_skipflash(ar->arHifDevice);
+ }
+
+ BMIInit();
+ {
+ struct bmi_target_info targ_info;
+
+ if (BMIGetTargetInfo(ar->arHifDevice, &targ_info) != A_OK) {
+ return;
+ }
+
+ ar->arVersion.target_ver = targ_info.target_ver;
+ ar->arTargetType = targ_info.target_type;
+ }
+
+ if (enableuartprint) {
+ A_UINT32 param;
+ param = 1;
+ if (BMIWriteMemory(ar->arHifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(ar, hi_serial_enable),
+ (A_UCHAR *)¶m,
+ 4)!= A_OK)
+ {
+ AR_DEBUG_PRINTF("BMIWriteMemory for enableuartprint failed \n");
+ return ;
+ }
+ AR_DEBUG_PRINTF("Serial console prints enabled\n");
+ }
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+ if(testmode) {
+ ar->arTargetMode = AR6000_TCMD_MODE;
+ }else {
+ ar->arTargetMode = AR6000_WLAN_MODE;
+ }
+#endif
+ if (enabletimerwar) {
+ A_UINT32 param;
+
+ if (BMIReadMemory(ar->arHifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
+ (A_UCHAR *)¶m,
+ 4)!= A_OK)
+ {
+ AR_DEBUG_PRINTF("BMIReadMemory for enabletimerwar failed \n");
+ return;
+ }
+
+ param |= HI_OPTION_TIMER_WAR;
+
+ if (BMIWriteMemory(ar->arHifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
+ (A_UCHAR *)¶m,
+ 4) != A_OK)
+ {
+ AR_DEBUG_PRINTF("BMIWriteMemory for enabletimerwar failed \n");
+ return;
+ }
+ AR_DEBUG_PRINTF("Timer WAR enabled\n");
+ }
+
+
+ /* since BMIInit is called in the driver layer, we have to set the block
+ * size here for the target */
+
+ if (A_FAILED(ar6000_SetHTCBlockSize(ar))) {
+ return;
+ }
+
+ spin_lock_init(&ar->arLock);
+
+ /* Don't install the init function if BMI is requested */
+ if(!bmienable)
+ {
+ dev->init = ar6000_init;
+ } else {
+ AR_DEBUG_PRINTF(" BMI enabled \n");
+ }
+
+ dev->open = &ar6000_open;
+ dev->stop = &ar6000_close;
+ dev->hard_start_xmit = &ar6000_data_tx;
+ dev->get_stats = &ar6000_get_stats;
+
+ /* dev->tx_timeout = ar6000_tx_timeout; */
+ dev->do_ioctl = &ar6000_ioctl;
+ dev->watchdog_timeo = AR6000_TX_TIMEOUT;
+ ar6000_ioctl_iwsetup(&ath_iw_handler_def);
+ dev->wireless_handlers = &ath_iw_handler_def;
+ ath_iw_handler_def.get_wireless_stats = ar6000_get_iwstats; /*Displayed via proc fs */
+
+ /*
+ * We need the OS to provide us with more headroom in order to
+ * perform dix to 802.3, WMI header encap, and the HTC header
+ */
+ dev->hard_header_len = ETH_HLEN + sizeof(ATH_LLC_SNAP_HDR) +
+ sizeof(WMI_DATA_HDR) + HTC_HEADER_LEN;
+
+ /* This runs the init function */
+ SET_NETDEV_DEV(dev, HIFGetOSDevice(ar->arHifDevice));
+ if (register_netdev(dev)) {
+ AR_DEBUG_PRINTF("ar6000_avail: register_netdev failed\n");
+ ar6000_destroy(dev, 0);
+ return;
+ }
+
+ HTCSetInstance(ar->arHtcTarget, ar);
+
+ /* We only register the device in the global list if we succeed. */
+ /* If the device is in the global list, it will be destroyed */
+ /* when the module is unloaded. */
+ ar6000_devices[device_index] = dev;
+
+ AR_DEBUG_PRINTF("ar6000_avail: name=%s htcTarget=0x%x, dev=0x%x (%d), ar=0x%x\n",
+ dev->name, (A_UINT32)HTCHandle, (A_UINT32)dev, device_index,
+ (A_UINT32)ar);
+}
+
+static void ar6000_target_failure(void *Instance, A_STATUS Status)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Instance;
+ WMI_TARGET_ERROR_REPORT_EVENT errEvent;
+ static A_BOOL sip = FALSE;
+
+ if (Status != A_OK) {
+ if (timer_pending(&ar->arHBChallengeResp.timer)) {
+ A_UNTIMEOUT(&ar->arHBChallengeResp.timer);
+ }
+
+ /* try dumping target assertion information (if any) */
+ ar6000_dump_target_assert_info(ar->arHifDevice,ar->arTargetType);
+
+ /*
+ * Fetch the logs from the target via the diagnostic
+ * window.
+ */
+ ar6000_dbglog_get_debug_logs(ar);
+
+ /* Report the error only once */
+ if (!sip) {
+ sip = TRUE;
+ errEvent.errorVal = WMI_TARGET_COM_ERR |
+ WMI_TARGET_FATAL_ERR;
+#ifdef SEND_EVENT_TO_APP
+ ar6000_send_event_to_app(ar, WMI_ERROR_REPORT_EVENTID,
+ (A_UINT8 *)&errEvent,
+ sizeof(WMI_TARGET_ERROR_REPORT_EVENT));
+#endif
+ }
+ }
+}
+
+static void
+ar6000_unavail_ev(void *Instance)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Instance;
+ /* NULL out it's entry in the global list */
+ ar6000_devices[ar->arDeviceIndex] = NULL;
+ ar6000_destroy(ar->arNetDev, 1);
+}
+
+/*
+ * We need to differentiate between the surprise and planned removal of the
+ * device because of the following consideration:
+ * - In case of surprise removal, the hcd already frees up the pending
+ * for the device and hence there is no need to unregister the function
+ * driver inorder to get these requests. For planned removal, the function
+ * driver has to explictly unregister itself to have the hcd return all the
+ * pending requests before the data structures for the devices are freed up.
+ * Note that as per the current implementation, the function driver will
+ * end up releasing all the devices since there is no API to selectively
+ * release a particular device.
+ * - Certain commands issued to the target can be skipped for surprise
+ * removal since they will anyway not go through.
+ */
+static void
+ar6000_destroy(struct net_device *dev, unsigned int unregister)
+{
+ AR_SOFTC_T *ar;
+
+ AR_DEBUG_PRINTF("+ar6000_destroy \n");
+
+ if((dev == NULL) || ((ar = netdev_priv(dev)) == NULL))
+ {
+ AR_DEBUG_PRINTF("%s(): Failed to get device structure.\n", __func__);
+ return;
+ }
+
+ /* Clear the tx counters */
+ memset(tx_attempt, 0, sizeof(tx_attempt));
+ memset(tx_post, 0, sizeof(tx_post));
+ memset(tx_complete, 0, sizeof(tx_complete));
+
+ /* Free up the device data structure */
+ if (unregister) {
+ unregister_netdev(dev);
+ } else {
+ ar6000_close(dev);
+ }
+
+ free_raw_buffers(ar);
+
+#ifndef free_netdev
+ kfree(dev);
+#else
+ free_netdev(dev);
+#endif
+
+ AR_DEBUG_PRINTF("-ar6000_destroy \n");
+}
+
+static void ar6000_detect_error(unsigned long ptr)
+{
+ struct net_device *dev = (struct net_device *)ptr;
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_TARGET_ERROR_REPORT_EVENT errEvent;
+
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ if (ar->arHBChallengeResp.outstanding) {
+ ar->arHBChallengeResp.missCnt++;
+ } else {
+ ar->arHBChallengeResp.missCnt = 0;
+ }
+
+ if (ar->arHBChallengeResp.missCnt > ar->arHBChallengeResp.missThres) {
+ /* Send Error Detect event to the application layer and do not reschedule the error detection module timer */
+ ar->arHBChallengeResp.missCnt = 0;
+ ar->arHBChallengeResp.seqNum = 0;
+ errEvent.errorVal = WMI_TARGET_COM_ERR | WMI_TARGET_FATAL_ERR;
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+#ifdef SEND_EVENT_TO_APP
+ ar6000_send_event_to_app(ar, WMI_ERROR_REPORT_EVENTID,
+ (A_UINT8 *)&errEvent,
+ sizeof(WMI_TARGET_ERROR_REPORT_EVENT));
+#endif
+ return;
+ }
+
+ /* Generate the sequence number for the next challenge */
+ ar->arHBChallengeResp.seqNum++;
+ ar->arHBChallengeResp.outstanding = TRUE;
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ /* Send the challenge on the control channel */
+ if (wmi_get_challenge_resp_cmd(ar->arWmi, ar->arHBChallengeResp.seqNum, DRV_HB_CHALLENGE) != A_OK) {
+ AR_DEBUG_PRINTF("Unable to send heart beat challenge\n");
+ }
+
+
+ /* Reschedule the timer for the next challenge */
+ A_TIMEOUT_MS(&ar->arHBChallengeResp.timer, ar->arHBChallengeResp.frequency * 1000, 0);
+}
+
+void ar6000_init_profile_info(AR_SOFTC_T *ar)
+{
+ ar->arSsidLen = 0;
+ A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
+ ar->arNetworkType = INFRA_NETWORK;
+ ar->arDot11AuthMode = OPEN_AUTH;
+ ar->arAuthMode = NONE_AUTH;
+ ar->arPairwiseCrypto = NONE_CRYPT;
+ ar->arPairwiseCryptoLen = 0;
+ ar->arGroupCrypto = NONE_CRYPT;
+ ar->arGroupCryptoLen = 0;
+ A_MEMZERO(ar->arWepKeyList, sizeof(ar->arWepKeyList));
+ A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
+ A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
+ ar->arBssChannel = 0;
+}
+
+static void
+ar6000_init_control_info(AR_SOFTC_T *ar)
+{
+ ar->arWmiEnabled = FALSE;
+ ar6000_init_profile_info(ar);
+ ar->arDefTxKeyIndex = 0;
+ A_MEMZERO(ar->arWepKeyList, sizeof(ar->arWepKeyList));
+ ar->arChannelHint = 0;
+ ar->arListenInterval = MAX_LISTEN_INTERVAL;
+ ar->arVersion.host_ver = AR6K_SW_VERSION;
+ ar->arRssi = 0;
+ ar->arTxPwr = 0;
+ ar->arTxPwrSet = FALSE;
+ ar->arSkipScan = 0;
+ ar->arBeaconInterval = 0;
+ ar->arBitRate = 0;
+ ar->arMaxRetries = 0;
+ ar->arWmmEnabled = TRUE;
+}
+
+static int
+ar6000_open(struct net_device *dev)
+{
+ /* Wake up the queues */
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int
+ar6000_close(struct net_device *dev)
+{
+ AR_SOFTC_T *ar = netdev_priv(dev);
+
+ /* Stop the transmit queues */
+ netif_stop_queue(dev);
+
+ /* Disable the target and the interrupts associated with it */
+ if (ar->arWmiReady == TRUE)
+ {
+ if (!bypasswmi)
+ {
+ if (ar->arConnected == TRUE || ar->arConnectPending == TRUE)
+ {
+ AR_DEBUG_PRINTF("%s(): Disconnect\n", __func__);
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ ar6000_init_profile_info(ar);
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ wmi_disconnect_cmd(ar->arWmi);
+ }
+
+ ar6000_dbglog_get_debug_logs(ar);
+ ar->arWmiReady = FALSE;
+ ar->arConnected = FALSE;
+ ar->arConnectPending = FALSE;
+ wmi_shutdown(ar->arWmi);
+ ar->arWmiEnabled = FALSE;
+ ar->arWmi = NULL;
+ ar->arWlanState = WLAN_ENABLED;
+#ifdef USER_KEYS
+ ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
+ ar->user_key_ctrl = 0;
+#endif
+ }
+
+ AR_DEBUG_PRINTF("%s(): WMI stopped\n", __func__);
+ }
+ else
+ {
+ AR_DEBUG_PRINTF("%s(): WMI not ready 0x%08x 0x%08x\n",
+ __func__, (unsigned int) ar, (unsigned int) ar->arWmi);
+
+ /* Shut down WMI if we have started it */
+ if(ar->arWmiEnabled == TRUE)
+ {
+ AR_DEBUG_PRINTF("%s(): Shut down WMI\n", __func__);
+ wmi_shutdown(ar->arWmi);
+ ar->arWmiEnabled = FALSE;
+ ar->arWmi = NULL;
+ }
+ }
+
+ /* stop HTC */
+ HTCStop(ar->arHtcTarget);
+
+ /* set the instance to NULL so we do not get called back on remove incase we
+ * we're explicity destroyed by module unload */
+ HTCSetInstance(ar->arHtcTarget, NULL);
+
+ if (resetok) {
+ /* try to reset the device if we can
+ * The driver may have been configure NOT to reset the target during
+ * a debug session */
+ AR_DEBUG_PRINTF(" Attempting to reset target on instance destroy.... \n");
+ ar6000_reset_device(ar->arHifDevice, ar->arTargetType);
+ } else {
+ AR_DEBUG_PRINTF(" Host does not want target reset. \n");
+ }
+
+ /* Done with cookies */
+ ar6000_cookie_cleanup(ar);
+
+ /* Cleanup BMI */
+ BMIInit();
+
+ return 0;
+}
+
+/* connect to a service */
+static A_STATUS ar6000_connectservice(AR_SOFTC_T *ar,
+ HTC_SERVICE_CONNECT_REQ *pConnect,
+ WMI_PRI_STREAM_ID WmiStreamID,
+ char *pDesc)
+{
+ A_STATUS status;
+ HTC_SERVICE_CONNECT_RESP response;
+
+ do {
+
+ A_MEMZERO(&response,sizeof(response));
+
+ status = HTCConnectService(ar->arHtcTarget,
+ pConnect,
+ &response);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(" Failed to connect to %s service status:%d \n", pDesc, status);
+ break;
+ }
+
+ if (WmiStreamID == WMI_NOT_MAPPED) {
+ /* done */
+ break;
+ }
+
+ /* set endpoint mapping for the WMI stream in the driver layer */
+ arSetWMIStream2EndpointIDMap(ar,WmiStreamID,response.Endpoint);
+
+ } while (FALSE);
+
+ return status;
+}
+
+static void ar6000_TxDataCleanup(AR_SOFTC_T *ar)
+{
+ /* flush all the data (non-control) streams
+ * we only flush packets that are tagged as data, we leave any control packets that
+ * were in the TX queues alone */
+ HTCFlushEndpoint(ar->arHtcTarget,
+ arWMIStream2EndpointID(ar,WMI_BEST_EFFORT_PRI),
+ AR6K_DATA_PKT_TAG);
+ HTCFlushEndpoint(ar->arHtcTarget,
+ arWMIStream2EndpointID(ar,WMI_LOW_PRI),
+ AR6K_DATA_PKT_TAG);
+ HTCFlushEndpoint(ar->arHtcTarget,
+ arWMIStream2EndpointID(ar,WMI_HIGH_PRI),
+ AR6K_DATA_PKT_TAG);
+ HTCFlushEndpoint(ar->arHtcTarget,
+ arWMIStream2EndpointID(ar,WMI_HIGHEST_PRI),
+ AR6K_DATA_PKT_TAG);
+}
+
+/* This function does one time initialization for the lifetime of the device */
+int ar6000_init(struct net_device *dev)
+{
+ AR_SOFTC_T *ar;
+ A_STATUS status;
+ A_INT32 timeleft;
+
+ if((ar = netdev_priv(dev)) == NULL)
+ {
+ return(-EIO);
+ }
+
+ /* Do we need to finish the BMI phase */
+ if(BMIDone(ar->arHifDevice) != A_OK)
+ {
+ return -EIO;
+ }
+
+ if (!bypasswmi)
+ {
+#if 0 /* TBDXXX */
+ if (ar->arVersion.host_ver != ar->arVersion.target_ver) {
+ A_PRINTF("WARNING: Host version 0x%x does not match Target "
+ " version 0x%x!\n",
+ ar->arVersion.host_ver, ar->arVersion.target_ver);
+ }
+#endif
+
+ /* Indicate that WMI is enabled (although not ready yet) */
+ ar->arWmiEnabled = TRUE;
+ if ((ar->arWmi = wmi_init((void *) ar)) == NULL)
+ {
+ AR_DEBUG_PRINTF("%s() Failed to initialize WMI.\n", __func__);
+ return(-EIO);
+ }
+
+ AR_DEBUG_PRINTF("%s() Got WMI @ 0x%08x.\n", __func__,
+ (unsigned int) ar->arWmi);
+ }
+
+ do {
+ HTC_SERVICE_CONNECT_REQ connect;
+
+ /* the reason we have to wait for the target here is that the driver layer
+ * has to init BMI in order to set the host block size,
+ */
+ status = HTCWaitTarget(ar->arHtcTarget);
+
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ A_MEMZERO(&connect,sizeof(connect));
+ /* meta data is unused for now */
+ connect.pMetaData = NULL;
+ connect.MetaDataLength = 0;
+ /* these fields are the same for all service endpoints */
+ connect.EpCallbacks.pContext = ar;
+ connect.EpCallbacks.EpTxComplete = ar6000_tx_complete;
+ connect.EpCallbacks.EpRecv = ar6000_rx;
+ connect.EpCallbacks.EpRecvRefill = ar6000_rx_refill;
+ connect.EpCallbacks.EpSendFull = ar6000_tx_queue_full;
+ connect.EpCallbacks.EpSendAvail = ar6000_tx_queue_avail;
+ /* set the max queue depth so that our ar6000_tx_queue_full handler gets called.
+ * Linux has the peculiarity of not providing flow control between the
+ * NIC and the network stack. There is no API to indicate that a TX packet
+ * was sent which could provide some back pressure to the network stack.
+ * Under linux you would have to wait till the network stack consumed all sk_buffs
+ * before any back-flow kicked in. Which isn't very friendly.
+ * So we have to manage this ourselves */
+ connect.MaxSendQueueDepth = 32;
+
+ /* connect to control service */
+ connect.ServiceID = WMI_CONTROL_SVC;
+ status = ar6000_connectservice(ar,
+ &connect,
+ WMI_CONTROL_PRI,
+ "WMI CONTROL");
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ /* for the remaining data services set the connection flag to reduce dribbling,
+ * if configured to do so */
+ if (reduce_credit_dribble) {
+ connect.ConnectionFlags |= HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE;
+ /* the credit dribble trigger threshold is (reduce_credit_dribble - 1) for a value
+ * of 0-3 */
+ connect.ConnectionFlags &= ~HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK;
+ connect.ConnectionFlags |=
+ ((A_UINT16)reduce_credit_dribble - 1) & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK;
+ }
+ /* connect to best-effort service */
+ connect.ServiceID = WMI_DATA_BE_SVC;
+
+ status = ar6000_connectservice(ar,
+ &connect,
+ WMI_BEST_EFFORT_PRI,
+ "WMI DATA BE");
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ /* connect to back-ground
+ * map this to WMI LOW_PRI */
+ connect.ServiceID = WMI_DATA_BK_SVC;
+ status = ar6000_connectservice(ar,
+ &connect,
+ WMI_LOW_PRI,
+ "WMI DATA BK");
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ /* connect to Video service, map this to
+ * to HI PRI */
+ connect.ServiceID = WMI_DATA_VI_SVC;
+ status = ar6000_connectservice(ar,
+ &connect,
+ WMI_HIGH_PRI,
+ "WMI DATA VI");
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ /* connect to VO service, this is currently not
+ * mapped to a WMI priority stream due to historical reasons.
+ * WMI originally defined 3 priorities over 3 mailboxes
+ * We can change this when WMI is reworked so that priorities are not
+ * dependent on mailboxes */
+ connect.ServiceID = WMI_DATA_VO_SVC;
+ status = ar6000_connectservice(ar,
+ &connect,
+ WMI_HIGHEST_PRI,
+ "WMI DATA VO");
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ A_ASSERT(arWMIStream2EndpointID(ar,WMI_CONTROL_PRI) != 0);
+ A_ASSERT(arWMIStream2EndpointID(ar,WMI_BEST_EFFORT_PRI) != 0);
+ A_ASSERT(arWMIStream2EndpointID(ar,WMI_LOW_PRI) != 0);
+ A_ASSERT(arWMIStream2EndpointID(ar,WMI_HIGH_PRI) != 0);
+ A_ASSERT(arWMIStream2EndpointID(ar,WMI_HIGHEST_PRI) != 0);
+ } while (FALSE);
+
+ if (A_FAILED(status)) {
+ return (-EIO);
+ }
+
+ /*
+ * give our connected endpoints some buffers
+ */
+ ar6000_rx_refill(ar, arWMIStream2EndpointID(ar,WMI_CONTROL_PRI));
+
+ ar6000_rx_refill(ar, arWMIStream2EndpointID(ar,WMI_BEST_EFFORT_PRI));
+
+ /*
+ * We will post the receive buffers only for SPE testing and so we are
+ * making it conditional on the 'bypasswmi' flag.
+ */
+ if (bypasswmi) {
+ ar6000_rx_refill(ar,arWMIStream2EndpointID(ar,WMI_LOW_PRI));
+ ar6000_rx_refill(ar,arWMIStream2EndpointID(ar,WMI_HIGH_PRI));
+ }
+
+ /* setup credit distribution */
+ ar6000_setup_credit_dist(ar->arHtcTarget, &ar->arCreditStateInfo);
+
+ /* Since cookies are used for HTC transports, they should be */
+ /* initialized prior to enabling HTC. */
+ ar6000_cookie_init(ar);
+
+ /* start HTC */
+ status = HTCStart(ar->arHtcTarget);
+
+ if (status != A_OK) {
+ if (ar->arWmiEnabled == TRUE) {
+ wmi_shutdown(ar->arWmi);
+ ar->arWmiEnabled = FALSE;
+ ar->arWmi = NULL;
+ }
+ ar6000_cookie_cleanup(ar);
+ return -EIO;
+ }
+
+ if (!bypasswmi) {
+ /* Wait for Wmi event to be ready */
+ timeleft = wait_event_interruptible_timeout(arEvent,
+ (ar->arWmiReady == TRUE), wmitimeout * HZ);
+
+ if(!timeleft || signal_pending(current))
+ {
+ AR_DEBUG_PRINTF("WMI is not ready or wait was interrupted\n");
+#if defined(DWSIM) /* TBDXXX */
+ AR_DEBUG_PRINTF(".....but proceed anyway.\n");
+#else
+ return -EIO;
+#endif
+ }
+
+ AR_DEBUG_PRINTF("%s() WMI is ready\n", __func__);
+
+ /* Communicate the wmi protocol verision to the target */
+ if ((ar6000_set_host_app_area(ar)) != A_OK) {
+ AR_DEBUG_PRINTF("Unable to set the host app area\n");
+ }
+ }
+
+ ar->arNumDataEndPts = 1;
+
+ return(0);
+}
+
+
+void
+ar6000_bitrate_rx(void *devt, A_INT32 rateKbps)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+
+ ar->arBitRate = rateKbps;
+ wake_up(&arEvent);
+}
+
+void
+ar6000_ratemask_rx(void *devt, A_UINT16 ratemask)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+
+ ar->arRateMask = ratemask;
+ wake_up(&arEvent);
+}
+
+void
+ar6000_txPwr_rx(void *devt, A_UINT8 txPwr)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+
+ ar->arTxPwr = txPwr;
+ wake_up(&arEvent);
+}
+
+
+void
+ar6000_channelList_rx(void *devt, A_INT8 numChan, A_UINT16 *chanList)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+
+ A_MEMCPY(ar->arChannelList, chanList, numChan * sizeof (A_UINT16));
+ ar->arNumChannels = numChan;
+
+ wake_up(&arEvent);
+}
+
+A_UINT8
+ar6000_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, A_UINT32 * mapNo)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ A_UINT8 *datap;
+ ATH_MAC_HDR *macHdr;
+ A_UINT32 i, eptMap;
+
+ (*mapNo) = 0;
+ datap = A_NETBUF_DATA(skb);
+ macHdr = (ATH_MAC_HDR *)(datap + sizeof(WMI_DATA_HDR));
+ if (IEEE80211_IS_MULTICAST(macHdr->dstMac)) {
+ return ENDPOINT_2;
+ }
+
+ eptMap = -1;
+ for (i = 0; i < ar->arNodeNum; i ++) {
+ if (IEEE80211_ADDR_EQ(macHdr->dstMac, ar->arNodeMap[i].macAddress)) {
+ (*mapNo) = i + 1;
+ ar->arNodeMap[i].txPending ++;
+ return ar->arNodeMap[i].epId;
+ }
+
+ if ((eptMap == -1) && !ar->arNodeMap[i].txPending) {
+ eptMap = i;
+ }
+ }
+
+ if (eptMap == -1) {
+ eptMap = ar->arNodeNum;
+ ar->arNodeNum ++;
+ A_ASSERT(ar->arNodeNum <= MAX_NODE_NUM);
+ }
+
+ A_MEMCPY(ar->arNodeMap[eptMap].macAddress, macHdr->dstMac, IEEE80211_ADDR_LEN);
+
+ for (i = ENDPOINT_2; i <= ENDPOINT_5; i ++) {
+ if (!ar->arTxPending[i]) {
+ ar->arNodeMap[eptMap].epId = i;
+ break;
+ }
+ // No free endpoint is available, start redistribution on the inuse endpoints.
+ if (i == ENDPOINT_5) {
+ ar->arNodeMap[eptMap].epId = ar->arNexEpId;
+ ar->arNexEpId ++;
+ if (ar->arNexEpId > ENDPOINT_5) {
+ ar->arNexEpId = ENDPOINT_2;
+ }
+ }
+ }
+
+ (*mapNo) = eptMap + 1;
+ ar->arNodeMap[eptMap].txPending ++;
+
+ return ar->arNodeMap[eptMap].epId;
+}
+
+#ifdef DEBUG
+static void ar6000_dump_skb(struct sk_buff *skb)
+{
+ u_char *ch;
+ for (ch = A_NETBUF_DATA(skb);
+ (A_UINT32)ch < ((A_UINT32)A_NETBUF_DATA(skb) +
+ A_NETBUF_LEN(skb)); ch++)
+ {
+ AR_DEBUG_PRINTF("%2.2x ", *ch);
+ }
+ AR_DEBUG_PRINTF("\n");
+}
+#endif
+
+static int
+ar6000_data_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_PRI_STREAM_ID streamID = WMI_NOT_MAPPED;
+ A_UINT32 mapNo = 0;
+ int len;
+ struct ar_cookie *cookie;
+ A_BOOL checkAdHocPsMapping = FALSE;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
+ skb->list = NULL;
+#endif
+
+ AR_DEBUG2_PRINTF("ar6000_data_tx start - skb=0x%x, data=0x%x, len=0x%x\n",
+ (A_UINT32)skb, (A_UINT32)A_NETBUF_DATA(skb),
+ A_NETBUF_LEN(skb));
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+ /* TCMD doesnt support any data, free the buf and return */
+ if(ar->arTargetMode == AR6000_TCMD_MODE) {
+ A_NETBUF_FREE(skb);
+ return 0;
+ }
+#endif
+ do {
+
+ if (ar->arWmiReady == FALSE && bypasswmi == 0) {
+ break;
+ }
+
+#ifdef BLOCK_TX_PATH_FLAG
+ if (blocktx) {
+ break;
+ }
+#endif /* BLOCK_TX_PATH_FLAG */
+
+ if (ar->arWmiEnabled) {
+ if (A_NETBUF_HEADROOM(skb) < dev->hard_header_len) {
+ struct sk_buff *newbuf;
+ /*
+ * We really should have gotten enough headroom but sometimes
+ * we still get packets with not enough headroom. Copy the packet.
+ */
+ len = A_NETBUF_LEN(skb);
+ newbuf = A_NETBUF_ALLOC(len);
+ if (newbuf == NULL) {
+ break;
+ }
+ A_NETBUF_PUT(newbuf, len);
+ A_MEMCPY(A_NETBUF_DATA(newbuf), A_NETBUF_DATA(skb), len);
+ A_NETBUF_FREE(skb);
+ skb = newbuf;
+ /* fall through and assemble header */
+ }
+
+ if (wmi_dix_2_dot3(ar->arWmi, skb) != A_OK) {
+ AR_DEBUG_PRINTF("ar6000_data_tx - wmi_dix_2_dot3 failed\n");
+ break;
+ }
+
+ if (wmi_data_hdr_add(ar->arWmi, skb, DATA_MSGTYPE) != A_OK) {
+ AR_DEBUG_PRINTF("ar6000_data_tx - wmi_data_hdr_add failed\n");
+ break;
+ }
+
+ if ((ar->arNetworkType == ADHOC_NETWORK) &&
+ ar->arIbssPsEnable && ar->arConnected) {
+ /* flag to check adhoc mapping once we take the lock below: */
+ checkAdHocPsMapping = TRUE;
+
+ } else {
+ /* get the stream mapping */
+ if (ar->arWmmEnabled) {
+ streamID = wmi_get_stream_id(ar->arWmi,
+ wmi_implicit_create_pstream(ar->arWmi, skb, UPLINK_TRAFFIC, UNDEFINED_PRI));
+ } else {
+ streamID = WMI_BEST_EFFORT_PRI;
+ }
+ }
+
+ } else {
+ struct iphdr *ipHdr;
+ /*
+ * the endpoint is directly based on the TOS field in the IP
+ * header **** only for testing ******
+ */
+ ipHdr = A_NETBUF_DATA(skb) + sizeof(ATH_MAC_HDR);
+ /* here we map the TOS field to an endpoint number, this is for
+ * the endpointping test application */
+ streamID = IP_TOS_TO_WMI_PRI(ipHdr->tos);
+ }
+
+ } while (FALSE);
+
+ /* did we succeed ? */
+ if ((streamID == WMI_NOT_MAPPED) && !checkAdHocPsMapping) {
+ /* cleanup and exit */
+ A_NETBUF_FREE(skb);
+ AR6000_STAT_INC(ar, tx_dropped);
+ AR6000_STAT_INC(ar, tx_aborted_errors);
+ return 0;
+ }
+
+ cookie = NULL;
+
+ /* take the lock to protect driver data */
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ do {
+
+ if (checkAdHocPsMapping) {
+ streamID = ar6000_ibss_map_epid(skb, dev, &mapNo);
+ }
+
+ A_ASSERT(streamID != WMI_NOT_MAPPED);
+
+ /* validate that the endpoint is connected */
+ if (arWMIStream2EndpointID(ar,streamID) == 0) {
+ AR_DEBUG_PRINTF("Stream %d is NOT mapped!\n",streamID);
+ break;
+ }
+ /* allocate resource for this packet */
+ cookie = ar6000_alloc_cookie(ar);
+
+ if (cookie != NULL) {
+ /* update counts while the lock is held */
+ ar->arTxPending[streamID]++;
+ ar->arTotalTxDataPending++;
+ }
+
+ } while (FALSE);
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ if (cookie != NULL) {
+ cookie->arc_bp[0] = (A_UINT32)skb;
+ cookie->arc_bp[1] = mapNo;
+ SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
+ cookie,
+ A_NETBUF_DATA(skb),
+ A_NETBUF_LEN(skb),
+ arWMIStream2EndpointID(ar,streamID),
+ AR6K_DATA_PKT_TAG);
+
+#ifdef DEBUG
+ if (debugdriver >= 3) {
+ ar6000_dump_skb(skb);
+ }
+#endif
+ /* HTC interface is asynchronous, if this fails, cleanup will happen in
+ * the ar6000_tx_complete callback */
+ HTCSendPkt(ar->arHtcTarget, &cookie->HtcPkt);
+ } else {
+ /* no packet to send, cleanup */
+ A_NETBUF_FREE(skb);
+ AR6000_STAT_INC(ar, tx_dropped);
+ AR6000_STAT_INC(ar, tx_aborted_errors);
+ }
+
+ return 0;
+}
+
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+static void
+tvsub(register struct timeval *out, register struct timeval *in)
+{
+ if((out->tv_usec -= in->tv_usec) < 0) {
+ out->tv_sec--;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+void
+applyAPTCHeuristics(AR_SOFTC_T *ar)
+{
+ A_UINT32 duration;
+ A_UINT32 numbytes;
+ A_UINT32 throughput;
+ struct timeval ts;
+ A_STATUS status;
+
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ if ((enableAPTCHeuristics) && (!aptcTR.timerScheduled)) {
+ do_gettimeofday(&ts);
+ tvsub(&ts, &aptcTR.samplingTS);
+ duration = ts.tv_sec * 1000 + ts.tv_usec / 1000; /* ms */
+ numbytes = aptcTR.bytesTransmitted + aptcTR.bytesReceived;
+
+ if (duration > APTC_TRAFFIC_SAMPLING_INTERVAL) {
+ /* Initialize the time stamp and byte count */
+ aptcTR.bytesTransmitted = aptcTR.bytesReceived = 0;
+ do_gettimeofday(&aptcTR.samplingTS);
+
+ /* Calculate and decide based on throughput thresholds */
+ throughput = ((numbytes * 8) / duration);
+ if (throughput > APTC_UPPER_THROUGHPUT_THRESHOLD) {
+ /* Disable Sleep and schedule a timer */
+ A_ASSERT(ar->arWmiReady == TRUE);
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ status = wmi_powermode_cmd(ar->arWmi, MAX_PERF_POWER);
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ A_TIMEOUT_MS(&aptcTimer, APTC_TRAFFIC_SAMPLING_INTERVAL, 0);
+ aptcTR.timerScheduled = TRUE;
+ }
+ }
+ }
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+}
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+static void
+ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *) Context;
+
+ if (Endpoint == arWMIStream2EndpointID(ar,WMI_CONTROL_PRI)) {
+ if (!bypasswmi) {
+ /* under normal WMI if this is getting full, then something is running rampant
+ * the host should not be exhausting the WMI queue with too many commands
+ * the only exception to this is during testing using endpointping */
+
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ /* set flag to handle subsequent messages */
+ ar->arWMIControlEpFull = TRUE;
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ AR_DEBUG_PRINTF("WMI Control Endpoint is FULL!!! \n");
+ }
+ } else {
+ /* one of the data endpoints queues is getting full..need to stop network stack
+ * the queue will resume after credits received */
+ netif_stop_queue(ar->arNetDev);
+ }
+}
+
+static void
+ar6000_tx_queue_avail(void *Context, HTC_ENDPOINT_ID Endpoint)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
+
+ if (Endpoint == arWMIStream2EndpointID(ar,WMI_CONTROL_PRI)) {
+ /* FIXME: what do for it? */
+ } else {
+ /* Wake up interface, rescheduling prevented. */
+ if (ar->arConnected == TRUE || bypasswmi)
+ netif_wake_queue(ar->arNetDev);
+ }
+}
+
+static void
+ar6000_tx_complete(void *Context, HTC_PACKET *pPacket)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
+ void *cookie = (void *)pPacket->pPktContext;
+ struct sk_buff *skb = NULL;
+ A_UINT32 mapNo = 0;
+ A_STATUS status;
+ struct ar_cookie * ar_cookie;
+ WMI_PRI_STREAM_ID streamID;
+ A_BOOL wakeEvent = FALSE;
+
+ status = pPacket->Status;
+ ar_cookie = (struct ar_cookie *)cookie;
+ skb = (struct sk_buff *)ar_cookie->arc_bp[0];
+ streamID = arEndpoint2WMIStreamID(ar,pPacket->Endpoint);
+ mapNo = ar_cookie->arc_bp[1];
+
+ A_ASSERT(skb);
+ A_ASSERT(pPacket->pBuffer == A_NETBUF_DATA(skb));
+
+ if (A_SUCCESS(status)) {
+ A_ASSERT(pPacket->ActualLength == A_NETBUF_LEN(skb));
+ }
+
+ AR_DEBUG2_PRINTF("ar6000_tx_complete skb=0x%x data=0x%x len=0x%x sid=%d ",
+ (A_UINT32)skb, (A_UINT32)pPacket->pBuffer,
+ pPacket->ActualLength,
+ streamID);
+
+ /* lock the driver as we update internal state */
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ ar->arTxPending[streamID]--;
+
+ if ((streamID != WMI_CONTROL_PRI) || bypasswmi) {
+ ar->arTotalTxDataPending--;
+ }
+
+ if (streamID == WMI_CONTROL_PRI)
+ {
+ if (ar->arWMIControlEpFull) {
+ /* since this packet completed, the WMI EP is no longer full */
+ ar->arWMIControlEpFull = FALSE;
+ }
+
+ if (ar->arTxPending[streamID] == 0) {
+ wakeEvent = TRUE;
+ }
+ }
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF("%s() -TX ERROR, status: 0x%x\n", __func__,
+ status);
+ AR6000_STAT_INC(ar, tx_errors);
+ } else {
+ AR_DEBUG2_PRINTF("OK\n");
+ AR6000_STAT_INC(ar, tx_packets);
+ ar->arNetStats.tx_bytes += A_NETBUF_LEN(skb);
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+ aptcTR.bytesTransmitted += a_netbuf_to_len(skb);
+ applyAPTCHeuristics(ar);
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+ }
+
+ // TODO this needs to be looked at
+ if ((ar->arNetworkType == ADHOC_NETWORK) && ar->arIbssPsEnable
+ && (streamID != WMI_CONTROL_PRI) && mapNo)
+ {
+ mapNo --;
+ ar->arNodeMap[mapNo].txPending --;
+
+ if (!ar->arNodeMap[mapNo].txPending && (mapNo == (ar->arNodeNum - 1))) {
+ A_UINT32 i;
+ for (i = ar->arNodeNum; i > 0; i --) {
+ if (!ar->arNodeMap[i - 1].txPending) {
+ A_MEMZERO(&ar->arNodeMap[i - 1], sizeof(struct ar_node_mapping));
+ ar->arNodeNum --;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Freeing a cookie should not be contingent on either of */
+ /* these flags, just if we have a cookie or not. */
+ /* Can we even get here without a cookie? Fix later. */
+ if (ar->arWmiReady == TRUE || (bypasswmi))
+ {
+ ar6000_free_cookie(ar, cookie);
+ }
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ /* lock is released, we can freely call other kernel APIs */
+
+ /* this indirectly frees the HTC_PACKET */
+ A_NETBUF_FREE(skb);
+
+ if (wakeEvent) {
+ wake_up(&arEvent);
+ }
+}
+
+/*
+ * Receive event handler. This is called by HTC when a packet is received
+ */
+int pktcount;
+static void
+ar6000_rx(void *Context, HTC_PACKET *pPacket)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
+ struct sk_buff *skb = (struct sk_buff *)pPacket->pPktContext;
+ int minHdrLen;
+ A_STATUS status = pPacket->Status;
+ WMI_PRI_STREAM_ID streamID = arEndpoint2WMIStreamID(ar,pPacket->Endpoint);
+ HTC_ENDPOINT_ID ept = pPacket->Endpoint;
+
+ A_ASSERT((status != A_OK) || (pPacket->pBuffer == (A_NETBUF_DATA(skb) + HTC_HEADER_LEN)));
+
+ AR_DEBUG2_PRINTF("ar6000_rx ar=0x%x sid=%d, skb=0x%x, data=0x%x, len=0x%x ",
+ (A_UINT32)ar, streamID, (A_UINT32)skb, (A_UINT32)pPacket->pBuffer,
+ pPacket->ActualLength);
+ if (status != A_OK) {
+ AR_DEBUG2_PRINTF("ERR\n");
+ } else {
+ AR_DEBUG2_PRINTF("OK\n");
+ }
+
+ /* take lock to protect buffer counts
+ * and adaptive power throughput state */
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ ar->arRxBuffers[streamID]--;
+
+ if (A_SUCCESS(status)) {
+ AR6000_STAT_INC(ar, rx_packets);
+ ar->arNetStats.rx_bytes += pPacket->ActualLength;
+#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
+ aptcTR.bytesReceived += a_netbuf_to_len(skb);
+ applyAPTCHeuristics(ar);
+#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
+
+ A_NETBUF_PUT(skb, pPacket->ActualLength + HTC_HEADER_LEN);
+ A_NETBUF_PULL(skb, HTC_HEADER_LEN);
+
+#ifdef DEBUG
+ if (debugdriver >= 2) {
+ ar6000_dump_skb(skb);
+ }
+#endif /* DEBUG */
+ }
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ if (status != A_OK) {
+ AR6000_STAT_INC(ar, rx_errors);
+ A_NETBUF_FREE(skb);
+ } else if (ar->arWmiEnabled == TRUE) {
+ if (streamID == WMI_CONTROL_PRI) {
+ /*
+ * this is a wmi control msg
+ */
+ wmi_control_rx(ar->arWmi, skb);
+ } else {
+ WMI_DATA_HDR *dhdr = (WMI_DATA_HDR *)A_NETBUF_DATA(skb);
+ if (WMI_DATA_HDR_IS_MSG_TYPE(dhdr, CNTL_MSGTYPE)) {
+ /*
+ * this is a wmi control msg
+ */
+ /* strip off WMI hdr */
+ wmi_data_hdr_remove(ar->arWmi, skb);
+ wmi_control_rx(ar->arWmi, skb);
+ } else {
+ /*
+ * this is a wmi data packet
+ */
+ minHdrLen = sizeof (WMI_DATA_HDR) + sizeof(ATH_MAC_HDR) +
+ sizeof(ATH_LLC_SNAP_HDR);
+
+ if ((pPacket->ActualLength < minHdrLen) ||
+ (pPacket->ActualLength > AR6000_BUFFER_SIZE))
+ {
+ /*
+ * packet is too short or too long
+ */
+ AR_DEBUG_PRINTF("TOO SHORT or TOO LONG\n");
+ AR6000_STAT_INC(ar, rx_errors);
+ AR6000_STAT_INC(ar, rx_length_errors);
+ A_NETBUF_FREE(skb);
+ } else {
+ if (ar->arWmmEnabled) {
+ wmi_implicit_create_pstream(ar->arWmi, skb,
+ DNLINK_TRAFFIC, UNDEFINED_PRI);
+ }
+#if 0
+ /* Access RSSI values here */
+ AR_DEBUG_PRINTF("RSSI %d\n",
+ ((WMI_DATA_HDR *) A_NETBUF_DATA(skb))->rssi);
+#endif
+ wmi_data_hdr_remove(ar->arWmi, skb);
+ wmi_dot3_2_dix(ar->arWmi, skb);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ /*
+ * extra push and memcpy, for eth_type_trans() of 2.4 kernel
+ * will pull out hard_header_len bytes of the skb.
+ */
+ A_NETBUF_PUSH(skb, sizeof(WMI_DATA_HDR) + sizeof(ATH_LLC_SNAP_HDR) + HTC_HEADER_LEN);
+ A_MEMCPY(A_NETBUF_DATA(skb), A_NETBUF_DATA(skb) + sizeof(WMI_DATA_HDR) +
+ sizeof(ATH_LLC_SNAP_HDR) + HTC_HEADER_LEN, sizeof(ATH_MAC_HDR));
+#endif
+ if ((ar->arNetDev->flags & IFF_UP) == IFF_UP)
+ {
+ skb->dev = ar->arNetDev;
+ skb->protocol = eth_type_trans(skb, ar->arNetDev);
+ netif_rx(skb);
+ }
+ else
+ {
+ A_NETBUF_FREE(skb);
+ }
+ }
+ }
+ }
+ } else {
+ if ((ar->arNetDev->flags & IFF_UP) == IFF_UP)
+ {
+ skb->dev = ar->arNetDev;
+ skb->protocol = eth_type_trans(skb, ar->arNetDev);
+ netif_rx(skb);
+ }
+ else
+ {
+ A_NETBUF_FREE(skb);
+ }
+ }
+
+ if (status != A_ECANCELED) {
+ /*
+ * HTC provides A_ECANCELED status when it doesn't want to be refilled
+ * (probably due to a shutdown)
+ */
+ ar6000_rx_refill(Context, ept);
+ }
+
+
+}
+
+static void
+ar6000_rx_refill(void *Context, HTC_ENDPOINT_ID Endpoint)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
+ void *osBuf;
+ int RxBuffers;
+ int buffersToRefill;
+ HTC_PACKET *pPacket;
+ WMI_PRI_STREAM_ID streamId = arEndpoint2WMIStreamID(ar,Endpoint);
+
+ buffersToRefill = (int)AR6000_MAX_RX_BUFFERS -
+ (int)ar->arRxBuffers[streamId];
+
+ if (buffersToRefill <= 0) {
+ /* fast return, nothing to fill */
+ return;
+ }
+
+ AR_DEBUG2_PRINTF("ar6000_rx_refill: providing htc with %d buffers at eid=%d\n",
+ buffersToRefill, Endpoint);
+
+ for (RxBuffers = 0; RxBuffers < buffersToRefill; RxBuffers++) {
+ osBuf = A_NETBUF_ALLOC(AR6000_BUFFER_SIZE);
+ if (NULL == osBuf) {
+ break;
+ }
+ /* the HTC packet wrapper is at the head of the reserved area
+ * in the skb */
+ pPacket = (HTC_PACKET *)(A_NETBUF_HEAD(osBuf));
+ /* set re-fill info */
+ SET_HTC_PACKET_INFO_RX_REFILL(pPacket,osBuf,A_NETBUF_DATA(osBuf),AR6000_BUFFER_SIZE,Endpoint);
+ /* add this packet */
+ HTCAddReceivePkt(ar->arHtcTarget, pPacket);
+ }
+
+ /* update count */
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ ar->arRxBuffers[streamId] += RxBuffers;
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+}
+
+static struct net_device_stats *
+ar6000_get_stats(struct net_device *dev)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ return &ar->arNetStats;
+}
+
+static struct iw_statistics *
+ar6000_get_iwstats(struct net_device * dev)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ TARGET_STATS *pStats = &ar->arTargetStats;
+ struct iw_statistics * pIwStats = &ar->arIwStats;
+
+ if ((ar->arWmiReady == FALSE)
+ /*
+ * The in_atomic function is used to determine if the scheduling is
+ * allowed in the current context or not. This was introduced in 2.6
+ * From what I have read on the differences between 2.4 and 2.6, the
+ * 2.4 kernel did not support preemption and so this check might not
+ * be required for 2.4 kernels.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ || (in_atomic())
+#endif
+ )
+ {
+ pIwStats->status = 0;
+ pIwStats->qual.qual = 0;
+ pIwStats->qual.level =0;
+ pIwStats->qual.noise = 0;
+ pIwStats->discard.code =0;
+ pIwStats->discard.retries=0;
+ pIwStats->miss.beacon =0;
+ return pIwStats;
+ }
+ if (down_interruptible(&ar->arSem)) {
+ pIwStats->status = 0;
+ return pIwStats;
+ }
+
+
+ ar->statsUpdatePending = TRUE;
+
+ if(wmi_get_stats_cmd(ar->arWmi) != A_OK) {
+ up(&ar->arSem);
+ pIwStats->status = 0;
+ return pIwStats;
+ }
+
+ wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == FALSE, wmitimeout * HZ);
+
+ if (signal_pending(current)) {
+ AR_DEBUG_PRINTF("ar6000 : WMI get stats timeout \n");
+ up(&ar->arSem);
+ pIwStats->status = 0;
+ return pIwStats;
+ }
+ pIwStats->status = 1 ;
+ pIwStats->qual.qual = pStats->cs_aveBeacon_rssi;
+ pIwStats->qual.level =pStats->cs_aveBeacon_rssi + 161; /* noise is -95 dBm */
+ pIwStats->qual.noise = pStats->noise_floor_calibation;
+ pIwStats->discard.code = pStats->rx_decrypt_err;
+ pIwStats->discard.retries = pStats->tx_retry_cnt;
+ pIwStats->miss.beacon = pStats->cs_bmiss_cnt;
+ up(&ar->arSem);
+ return pIwStats;
+}
+
+void
+ar6000_ready_event(void *devt, A_UINT8 *datap, A_UINT8 phyCap)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+ struct net_device *dev = ar->arNetDev;
+
+ ar->arWmiReady = TRUE;
+ wake_up(&arEvent);
+ A_MEMCPY(dev->dev_addr, datap, AR6000_ETH_ADDR_LEN);
+ AR_DEBUG_PRINTF("mac address = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+
+ ar->arPhyCapability = phyCap;
+}
+
+A_UINT8
+ar6000_iptos_to_userPriority(A_UINT8 *pkt)
+{
+ struct iphdr *ipHdr = (struct iphdr *)pkt;
+ A_UINT8 userPriority;
+
+ /*
+ * IP Tos format :
+ * (Refer Pg 57 WMM-test-plan-v1.2)
+ * IP-TOS - 8bits
+ * : DSCP(6-bits) ECN(2-bits)
+ * : DSCP - P2 P1 P0 X X X
+ * where (P2 P1 P0) form 802.1D
+ */
+ userPriority = ipHdr->tos >> 5;
+ return (userPriority & 0x7);
+}
+
+void
+ar6000_connect_event(AR_SOFTC_T *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)
+{
+ union iwreq_data wrqu;
+ int i, beacon_ie_pos, assoc_resp_ie_pos, assoc_req_ie_pos;
+ static const char *tag1 = "ASSOCINFO(ReqIEs=";
+ static const char *tag2 = "ASSOCRESPIE=";
+ static const char *beaconIetag = "BEACONIE=";
+ char buf[WMI_CONTROL_MSG_MAX_LEN * 2 + sizeof(tag1)];
+ char *pos;
+ A_UINT8 key_op_ctrl;
+
+ A_MEMCPY(ar->arBssid, bssid, sizeof(ar->arBssid));
+ ar->arBssChannel = channel;
+
+ A_PRINTF("AR6000 connected event on freq %d ", channel);
+ A_PRINTF("with bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
+ " listenInterval=%d, beaconInterval = %d, beaconIeLen = %d assocReqLen=%d"
+ " assocRespLen =%d\n",
+ bssid[0], bssid[1], bssid[2],
+ bssid[3], bssid[4], bssid[5],
+ listenInterval, beaconInterval,
+ beaconIeLen, assocReqLen, assocRespLen);
+ if (networkType & ADHOC_NETWORK) {
+ if (networkType & ADHOC_CREATOR) {
+ A_PRINTF("Network: Adhoc (Creator)\n");
+ } else {
+ A_PRINTF("Network: Adhoc (Joiner)\n");
+ }
+ } else {
+ A_PRINTF("Network: Infrastructure\n");
+ }
+
+ if (beaconIeLen && (sizeof(buf) > (9 + beaconIeLen * 2))) {
+ AR_DEBUG_PRINTF("\nBeaconIEs= ");
+
+ beacon_ie_pos = 0;
+ A_MEMZERO(buf, sizeof(buf));
+ sprintf(buf, "%s", beaconIetag);
+ pos = buf + 9;
+ for (i = beacon_ie_pos; i < beacon_ie_pos + beaconIeLen; i++) {
+ AR_DEBUG_PRINTF("%2.2x ", assocInfo[i]);
+ sprintf(pos, "%2.2x", assocInfo[i]);
+ pos += 2;
+ }
+ AR_DEBUG_PRINTF("\n");
+
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+ }
+
+ if (assocRespLen && (sizeof(buf) > (12 + (assocRespLen * 2))))
+ {
+ assoc_resp_ie_pos = beaconIeLen + assocReqLen +
+ sizeof(A_UINT16) + /* capinfo*/
+ sizeof(A_UINT16) + /* status Code */
+ sizeof(A_UINT16) ; /* associd */
+ A_MEMZERO(buf, sizeof(buf));
+ sprintf(buf, "%s", tag2);
+ pos = buf + 12;
+ AR_DEBUG_PRINTF("\nAssocRespIEs= ");
+ /*
+ * The Association Response Frame w.o. the WLAN header is delivered to
+ * the host, so skip over to the IEs
+ */
+ for (i = assoc_resp_ie_pos; i < assoc_resp_ie_pos + assocRespLen - 6; i++)
+ {
+ AR_DEBUG_PRINTF("%2.2x ", assocInfo[i]);
+ sprintf(pos, "%2.2x", assocInfo[i]);
+ pos += 2;
+ }
+ AR_DEBUG_PRINTF("\n");
+
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+ }
+
+ if (assocReqLen && (sizeof(buf) > (17 + (assocReqLen * 2)))) {
+ /*
+ * assoc Request includes capability and listen interval. Skip these.
+ */
+ assoc_req_ie_pos = beaconIeLen +
+ sizeof(A_UINT16) + /* capinfo*/
+ sizeof(A_UINT16); /* listen interval */
+
+ A_MEMZERO(buf, sizeof(buf));
+ sprintf(buf, "%s", tag1);
+ pos = buf + 17;
+ AR_DEBUG_PRINTF("AssocReqIEs= ");
+ for (i = assoc_req_ie_pos; i < assoc_req_ie_pos + assocReqLen - 4; i++) {
+ AR_DEBUG_PRINTF("%2.2x ", assocInfo[i]);
+ sprintf(pos, "%2.2x", assocInfo[i]);
+ pos += 2;;
+ }
+ AR_DEBUG_PRINTF("\n");
+
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+ }
+
+#ifdef USER_KEYS
+ if (ar->user_savedkeys_stat == USER_SAVEDKEYS_STAT_RUN &&
+ ar->user_saved_keys.keyOk == TRUE)
+ {
+
+ key_op_ctrl = KEY_OP_VALID_MASK & ~KEY_OP_INIT_TSC;
+ if (ar->user_key_ctrl & AR6000_USER_SETKEYS_RSC_UNCHANGED) {
+ key_op_ctrl &= ~KEY_OP_INIT_RSC;
+ } else {
+ key_op_ctrl |= KEY_OP_INIT_RSC;
+ }
+ ar6000_reinstall_keys(ar, key_op_ctrl);
+ }
+#endif /* USER_KEYS */
+
+ /* flush data queues */
+ ar6000_TxDataCleanup(ar);
+
+ netif_start_queue(ar->arNetDev);
+
+ if ((OPEN_AUTH == ar->arDot11AuthMode) &&
+ (NONE_AUTH == ar->arAuthMode) &&
+ (WEP_CRYPT == ar->arPairwiseCrypto))
+ {
+ if (!ar->arConnected) {
+ ar6000_install_static_wep_keys(ar);
+ }
+ }
+
+ ar->arConnected = TRUE;
+ ar->arConnectPending = FALSE;
+
+ reconnect_flag = 0;
+
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ A_MEMCPY(wrqu.addr.sa_data, bssid, IEEE80211_ADDR_LEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(ar->arNetDev, SIOCGIWAP, &wrqu, NULL);
+ if ((ar->arNetworkType == ADHOC_NETWORK) && ar->arIbssPsEnable) {
+ A_MEMZERO(ar->arNodeMap, sizeof(ar->arNodeMap));
+ ar->arNodeNum = 0;
+ ar->arNexEpId = ENDPOINT_2;
+ }
+
+}
+
+void ar6000_set_numdataendpts(AR_SOFTC_T *ar, A_UINT32 num)
+{
+ A_ASSERT(num <= (HTC_MAILBOX_NUM_MAX - 1));
+ ar->arNumDataEndPts = num;
+}
+
+void
+ar6000_disconnect_event(AR_SOFTC_T *ar, A_UINT8 reason, A_UINT8 *bssid,
+ A_UINT8 assocRespLen, A_UINT8 *assocInfo, A_UINT16 protocolReasonStatus)
+{
+ A_UINT8 i;
+
+ A_PRINTF("AR6000 disconnected");
+ if (bssid[0] || bssid[1] || bssid[2] || bssid[3] || bssid[4] || bssid[5]) {
+ A_PRINTF(" from %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+ }
+ A_PRINTF("\n");
+
+ AR_DEBUG_PRINTF("\nDisconnect Reason is %d", reason);
+ AR_DEBUG_PRINTF("\nProtocol Reason/Status Code is %d", protocolReasonStatus);
+ AR_DEBUG_PRINTF("\nAssocResp Frame = %s",
+ assocRespLen ? " " : "NULL");
+ for (i = 0; i < assocRespLen; i++) {
+ if (!(i % 0x10)) {
+ AR_DEBUG_PRINTF("\n");
+ }
+ AR_DEBUG_PRINTF("%2.2x ", assocInfo[i]);
+ }
+ AR_DEBUG_PRINTF("\n");
+ /*
+ * If the event is due to disconnect cmd from the host, only they the target
+ * would stop trying to connect. Under any other condition, target would
+ * keep trying to connect.
+ *
+ */
+ if( reason == DISCONNECT_CMD)
+ {
+ ar->arConnectPending = FALSE;
+ } else {
+ ar->arConnectPending = TRUE;
+ if (((reason == ASSOC_FAILED) && (protocolReasonStatus == 0x11)) ||
+ ((reason == ASSOC_FAILED) && (protocolReasonStatus == 0x0) && (reconnect_flag == 1))) {
+ ar->arConnected = TRUE;
+ return;
+ }
+ }
+ ar->arConnected = FALSE;
+
+ if( (reason != CSERV_DISCONNECT) || (reconnect_flag != 1) ) {
+ reconnect_flag = 0;
+ }
+
+#ifdef USER_KEYS
+ if (reason != CSERV_DISCONNECT)
+ {
+ ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
+ ar->user_key_ctrl = 0;
+ }
+#endif /* USER_KEYS */
+
+ netif_stop_queue(ar->arNetDev);
+ A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
+ ar->arBssChannel = 0;
+ ar->arBeaconInterval = 0;
+
+ ar6000_TxDataCleanup(ar);
+}
+
+void
+ar6000_regDomain_event(AR_SOFTC_T *ar, A_UINT32 regCode)
+{
+ A_PRINTF("AR6000 Reg Code = 0x%x\n", regCode);
+ ar->arRegCode = regCode;
+}
+
+void
+ar6000_neighborReport_event(AR_SOFTC_T *ar, int numAps, WMI_NEIGHBOR_INFO *info)
+{
+ static const char *tag = "PRE-AUTH";
+ char buf[128];
+ union iwreq_data wrqu;
+ int i;
+
+ AR_DEBUG_PRINTF("AR6000 Neighbor Report Event\n");
+ for (i=0; i < numAps; info++, i++) {
+ AR_DEBUG_PRINTF("bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",
+ info->bssid[0], info->bssid[1], info->bssid[2],
+ info->bssid[3], info->bssid[4], info->bssid[5]);
+ if (info->bssFlags & WMI_PREAUTH_CAPABLE_BSS) {
+ AR_DEBUG_PRINTF("preauth-cap");
+ }
+ if (info->bssFlags & WMI_PMKID_VALID_BSS) {
+ AR_DEBUG_PRINTF(" pmkid-valid\n");
+ continue; /* we skip bss if the pmkid is already valid */
+ }
+ AR_DEBUG_PRINTF("\n");
+ snprintf(buf, sizeof(buf), "%s%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
+ tag,
+ info->bssid[0], info->bssid[1], info->bssid[2],
+ info->bssid[3], info->bssid[4], info->bssid[5],
+ i, info->bssFlags);
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+ }
+}
+
+void
+ar6000_tkip_micerr_event(AR_SOFTC_T *ar, A_UINT8 keyid, A_BOOL ismcast)
+{
+ static const char *tag = "MLME-MICHAELMICFAILURE.indication";
+ char buf[128];
+ union iwreq_data wrqu;
+
+ A_PRINTF("AR6000 TKIP MIC error received for keyid %d %scast\n",
+ keyid, ismcast ? "multi": "uni");
+ snprintf(buf, sizeof(buf), "%s(keyid=%d %scat)", tag, keyid,
+ ismcast ? "multi" : "uni");
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+}
+
+void
+ar6000_scanComplete_event(AR_SOFTC_T *ar, A_STATUS status)
+{
+ AR_DEBUG_PRINTF("AR6000 scan complete: %d\n", status);
+
+ ar->scan_complete = 1;
+ wake_up_interruptible(&ar6000_scan_queue);
+}
+
+void
+ar6000_targetStats_event(AR_SOFTC_T *ar, WMI_TARGET_STATS *pTarget)
+{
+ TARGET_STATS *pStats = &ar->arTargetStats;
+ A_UINT8 ac;
+
+ /*A_PRINTF("AR6000 updating target stats\n");*/
+ pStats->tx_packets += pTarget->txrxStats.tx_stats.tx_packets;
+ pStats->tx_bytes += pTarget->txrxStats.tx_stats.tx_bytes;
+ pStats->tx_unicast_pkts += pTarget->txrxStats.tx_stats.tx_unicast_pkts;
+ pStats->tx_unicast_bytes += pTarget->txrxStats.tx_stats.tx_unicast_bytes;
+ pStats->tx_multicast_pkts += pTarget->txrxStats.tx_stats.tx_multicast_pkts;
+ pStats->tx_multicast_bytes += pTarget->txrxStats.tx_stats.tx_multicast_bytes;
+ pStats->tx_broadcast_pkts += pTarget->txrxStats.tx_stats.tx_broadcast_pkts;
+ pStats->tx_broadcast_bytes += pTarget->txrxStats.tx_stats.tx_broadcast_bytes;
+ pStats->tx_rts_success_cnt += pTarget->txrxStats.tx_stats.tx_rts_success_cnt;
+ for(ac = 0; ac < WMM_NUM_AC; ac++)
+ pStats->tx_packet_per_ac[ac] += pTarget->txrxStats.tx_stats.tx_packet_per_ac[ac];
+ pStats->tx_errors += pTarget->txrxStats.tx_stats.tx_errors;
+ pStats->tx_failed_cnt += pTarget->txrxStats.tx_stats.tx_failed_cnt;
+ pStats->tx_retry_cnt += pTarget->txrxStats.tx_stats.tx_retry_cnt;
+ pStats->tx_rts_fail_cnt += pTarget->txrxStats.tx_stats.tx_rts_fail_cnt;
+ pStats->tx_unicast_rate = wmi_get_rate(pTarget->txrxStats.tx_stats.tx_unicast_rate);
+
+ pStats->rx_packets += pTarget->txrxStats.rx_stats.rx_packets;
+ pStats->rx_bytes += pTarget->txrxStats.rx_stats.rx_bytes;
+ pStats->rx_unicast_pkts += pTarget->txrxStats.rx_stats.rx_unicast_pkts;
+ pStats->rx_unicast_bytes += pTarget->txrxStats.rx_stats.rx_unicast_bytes;
+ pStats->rx_multicast_pkts += pTarget->txrxStats.rx_stats.rx_multicast_pkts;
+ pStats->rx_multicast_bytes += pTarget->txrxStats.rx_stats.rx_multicast_bytes;
+ pStats->rx_broadcast_pkts += pTarget->txrxStats.rx_stats.rx_broadcast_pkts;
+ pStats->rx_broadcast_bytes += pTarget->txrxStats.rx_stats.rx_broadcast_bytes;
+ pStats->rx_fragment_pkt += pTarget->txrxStats.rx_stats.rx_fragment_pkt;
+ pStats->rx_errors += pTarget->txrxStats.rx_stats.rx_errors;
+ pStats->rx_crcerr += pTarget->txrxStats.rx_stats.rx_crcerr;
+ pStats->rx_key_cache_miss += pTarget->txrxStats.rx_stats.rx_key_cache_miss;
+ pStats->rx_decrypt_err += pTarget->txrxStats.rx_stats.rx_decrypt_err;
+ pStats->rx_duplicate_frames += pTarget->txrxStats.rx_stats.rx_duplicate_frames;
+ pStats->rx_unicast_rate = wmi_get_rate(pTarget->txrxStats.rx_stats.rx_unicast_rate);
+
+
+ pStats->tkip_local_mic_failure
+ += pTarget->txrxStats.tkipCcmpStats.tkip_local_mic_failure;
+ pStats->tkip_counter_measures_invoked
+ += pTarget->txrxStats.tkipCcmpStats.tkip_counter_measures_invoked;
+ pStats->tkip_replays += pTarget->txrxStats.tkipCcmpStats.tkip_replays;
+ pStats->tkip_format_errors += pTarget->txrxStats.tkipCcmpStats.tkip_format_errors;
+ pStats->ccmp_format_errors += pTarget->txrxStats.tkipCcmpStats.ccmp_format_errors;
+ pStats->ccmp_replays += pTarget->txrxStats.tkipCcmpStats.ccmp_replays;
+
+
+ pStats->power_save_failure_cnt += pTarget->pmStats.power_save_failure_cnt;
+ pStats->noise_floor_calibation = pTarget->noise_floor_calibation;
+
+ pStats->cs_bmiss_cnt += pTarget->cservStats.cs_bmiss_cnt;
+ pStats->cs_lowRssi_cnt += pTarget->cservStats.cs_lowRssi_cnt;
+ pStats->cs_connect_cnt += pTarget->cservStats.cs_connect_cnt;
+ pStats->cs_disconnect_cnt += pTarget->cservStats.cs_disconnect_cnt;
+ pStats->cs_aveBeacon_snr = pTarget->cservStats.cs_aveBeacon_snr;
+ pStats->cs_aveBeacon_rssi = pTarget->cservStats.cs_aveBeacon_rssi;
+ pStats->cs_lastRoam_msec = pTarget->cservStats.cs_lastRoam_msec;
+ pStats->cs_snr = pTarget->cservStats.cs_snr;
+ pStats->cs_rssi = pTarget->cservStats.cs_rssi;
+
+ pStats->lq_val = pTarget->lqVal;
+
+ pStats->wow_num_pkts_dropped += pTarget->wowStats.wow_num_pkts_dropped;
+ pStats->wow_num_host_pkt_wakeups += pTarget->wowStats.wow_num_host_pkt_wakeups;
+ pStats->wow_num_host_event_wakeups += pTarget->wowStats.wow_num_host_event_wakeups;
+ pStats->wow_num_events_discarded += pTarget->wowStats.wow_num_events_discarded;
+
+ ar->statsUpdatePending = FALSE;
+ wake_up(&arEvent);
+}
+
+void
+ar6000_rssiThreshold_event(AR_SOFTC_T *ar, WMI_RSSI_THRESHOLD_VAL newThreshold, A_INT16 rssi)
+{
+ USER_RSSI_THOLD userRssiThold;
+
+ userRssiThold.tag = rssi_map[newThreshold].tag;
+ userRssiThold.rssi = rssi;
+ AR_DEBUG2_PRINTF("rssi Threshold range = %d tag = %d rssi = %d\n", newThreshold, userRssiThold.tag, rssi);
+#ifdef SEND_EVENT_TO_APP
+ ar6000_send_event_to_app(ar, WMI_RSSI_THRESHOLD_EVENTID,(A_UINT8 *)&userRssiThold, sizeof(USER_RSSI_THOLD));
+#endif
+}
+
+
+void
+ar6000_hbChallengeResp_event(AR_SOFTC_T *ar, A_UINT32 cookie, A_UINT32 source)
+{
+ if (source == APP_HB_CHALLENGE) {
+ /* Report it to the app in case it wants a positive acknowledgement */
+#ifdef SEND_EVENT_TO_APP
+ ar6000_send_event_to_app(ar, WMIX_HB_CHALLENGE_RESP_EVENTID,
+ (A_UINT8 *)&cookie, sizeof(cookie));
+#endif
+ } else {
+ /* This would ignore the replys that come in after their due time */
+ if (cookie == ar->arHBChallengeResp.seqNum) {
+ ar->arHBChallengeResp.outstanding = FALSE;
+ }
+ }
+}
+
+
+void
+ar6000_reportError_event(AR_SOFTC_T *ar, WMI_TARGET_ERROR_VAL errorVal)
+{
+ char *errString[] = {
+ [WMI_TARGET_PM_ERR_FAIL] "WMI_TARGET_PM_ERR_FAIL",
+ [WMI_TARGET_KEY_NOT_FOUND] "WMI_TARGET_KEY_NOT_FOUND",
+ [WMI_TARGET_DECRYPTION_ERR] "WMI_TARGET_DECRYPTION_ERR",
+ [WMI_TARGET_BMISS] "WMI_TARGET_BMISS",
+ [WMI_PSDISABLE_NODE_JOIN] "WMI_PSDISABLE_NODE_JOIN"
+ };
+
+ A_PRINTF("AR6000 Error on Target. Error = 0x%x\n", errorVal);
+
+ /* One error is reported at a time, and errorval is a bitmask */
+ if(errorVal & (errorVal - 1))
+ return;
+
+ A_PRINTF("AR6000 Error type = ");
+ switch(errorVal)
+ {
+ case WMI_TARGET_PM_ERR_FAIL:
+ case WMI_TARGET_KEY_NOT_FOUND:
+ case WMI_TARGET_DECRYPTION_ERR:
+ case WMI_TARGET_BMISS:
+ case WMI_PSDISABLE_NODE_JOIN:
+ A_PRINTF("%s\n", errString[errorVal]);
+ break;
+ default:
+ A_PRINTF("INVALID\n");
+ break;
+ }
+
+}
+
+
+void
+ar6000_cac_event(AR_SOFTC_T *ar, A_UINT8 ac, A_UINT8 cacIndication,
+ A_UINT8 statusCode, A_UINT8 *tspecSuggestion)
+{
+ WMM_TSPEC_IE *tspecIe;
+
+ /*
+ * This is the TSPEC IE suggestion from AP.
+ * Suggestion provided by AP under some error
+ * cases, could be helpful for the host app.
+ * Check documentation.
+ */
+ tspecIe = (WMM_TSPEC_IE *)tspecSuggestion;
+
+ /*
+ * What do we do, if we get TSPEC rejection? One thought
+ * that comes to mind is implictly delete the pstream...
+ */
+ A_PRINTF("AR6000 CAC notification. "
+ "AC = %d, cacIndication = 0x%x, statusCode = 0x%x\n",
+ ac, cacIndication, statusCode);
+}
+
+#define AR6000_PRINT_BSSID(_pBss) do { \
+ A_PRINTF("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",\
+ (_pBss)[0],(_pBss)[1],(_pBss)[2],(_pBss)[3],\
+ (_pBss)[4],(_pBss)[5]); \
+} while(0)
+
+void
+ar6000_roam_tbl_event(AR_SOFTC_T *ar, WMI_TARGET_ROAM_TBL *pTbl)
+{
+ A_UINT8 i;
+
+ A_PRINTF("ROAM TABLE NO OF ENTRIES is %d ROAM MODE is %d\n",
+ pTbl->numEntries, pTbl->roamMode);
+ for (i= 0; i < pTbl->numEntries; i++) {
+ A_PRINTF("[%d]bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ", i,
+ pTbl->bssRoamInfo[i].bssid[0], pTbl->bssRoamInfo[i].bssid[1],
+ pTbl->bssRoamInfo[i].bssid[2],
+ pTbl->bssRoamInfo[i].bssid[3],
+ pTbl->bssRoamInfo[i].bssid[4],
+ pTbl->bssRoamInfo[i].bssid[5]);
+ A_PRINTF("RSSI %d RSSIDT %d LAST RSSI %d UTIL %d ROAM_UTIL %d"
+ " BIAS %d\n",
+ pTbl->bssRoamInfo[i].rssi,
+ pTbl->bssRoamInfo[i].rssidt,
+ pTbl->bssRoamInfo[i].last_rssi,
+ pTbl->bssRoamInfo[i].util,
+ pTbl->bssRoamInfo[i].roam_util,
+ pTbl->bssRoamInfo[i].bias);
+ }
+}
+
+void
+ar6000_wow_list_event(struct ar6_softc *ar, A_UINT8 num_filters, WMI_GET_WOW_LIST_REPLY *wow_reply)
+{
+ A_UINT8 i,j;
+
+ /*Each event now contains exactly one filter, see bug 26613*/
+ A_PRINTF("WOW pattern %d of %d patterns\n", wow_reply->this_filter_num, wow_reply->num_filters);
+ A_PRINTF("wow mode = %s host mode = %s\n",
+ (wow_reply->wow_mode == 0? "disabled":"enabled"),
+ (wow_reply->host_mode == 1 ? "awake":"asleep"));
+
+
+ /*If there are no patterns, the reply will only contain generic
+ WoW information. Pattern information will exist only if there are
+ patterns present. Bug 26716*/
+
+ /* If this event contains pattern information, display it*/
+ if (wow_reply->this_filter_num) {
+ i=0;
+ A_PRINTF("id=%d size=%d offset=%d\n",
+ wow_reply->wow_filters[i].wow_filter_id,
+ wow_reply->wow_filters[i].wow_filter_size,
+ wow_reply->wow_filters[i].wow_filter_offset);
+ A_PRINTF("wow pattern = ");
+ for (j=0; j< wow_reply->wow_filters[i].wow_filter_size; j++) {
+ A_PRINTF("%2.2x",wow_reply->wow_filters[i].wow_filter_pattern[j]);
+ }
+
+ A_PRINTF("\nwow mask = ");
+ for (j=0; j< wow_reply->wow_filters[i].wow_filter_size; j++) {
+ A_PRINTF("%2.2x",wow_reply->wow_filters[i].wow_filter_mask[j]);
+ }
+ A_PRINTF("\n");
+ }
+}
+
+/*
+ * Report the Roaming related data collected on the target
+ */
+void
+ar6000_display_roam_time(WMI_TARGET_ROAM_TIME *p)
+{
+ A_PRINTF("Disconnect Data : BSSID: ");
+ AR6000_PRINT_BSSID(p->disassoc_bssid);
+ A_PRINTF(" RSSI %d DISASSOC Time %d NO_TXRX_TIME %d\n",
+ p->disassoc_bss_rssi,p->disassoc_time,
+ p->no_txrx_time);
+ A_PRINTF("Connect Data: BSSID: ");
+ AR6000_PRINT_BSSID(p->assoc_bssid);
+ A_PRINTF(" RSSI %d ASSOC Time %d TXRX_TIME %d\n",
+ p->assoc_bss_rssi,p->assoc_time,
+ p->allow_txrx_time);
+ A_PRINTF("Last Data Tx Time (b4 Disassoc) %d "\
+ "First Data Tx Time (after Assoc) %d\n",
+ p->last_data_txrx_time, p->first_data_txrx_time);
+}
+
+void
+ar6000_roam_data_event(AR_SOFTC_T *ar, WMI_TARGET_ROAM_DATA *p)
+{
+ switch (p->roamDataType) {
+ case ROAM_DATA_TIME:
+ ar6000_display_roam_time(&p->u.roamTime);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+ar6000_bssInfo_event_rx(AR_SOFTC_T *ar, A_UINT8 *datap, int len)
+{
+ struct sk_buff *skb;
+ WMI_BSS_INFO_HDR *bih = (WMI_BSS_INFO_HDR *)datap;
+
+
+ if (!ar->arMgmtFilter) {
+ return;
+ }
+ if (((ar->arMgmtFilter & IEEE80211_FILTER_TYPE_BEACON) &&
+ (bih->frameType != BEACON_FTYPE)) ||
+ ((ar->arMgmtFilter & IEEE80211_FILTER_TYPE_PROBE_RESP) &&
+ (bih->frameType != PROBERESP_FTYPE)))
+ {
+ return;
+ }
+
+ if ((skb = A_NETBUF_ALLOC_RAW(len)) != NULL) {
+
+ A_NETBUF_PUT(skb, len);
+ A_MEMCPY(A_NETBUF_DATA(skb), datap, len);
+ skb->dev = ar->arNetDev;
+ printk("MAC RAW...\n");
+// skb->mac.raw = A_NETBUF_DATA(skb);
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(0x0019);
+ netif_rx(skb);
+ }
+}
+
+A_UINT32 wmiSendCmdNum;
+
+A_STATUS
+ar6000_control_tx(void *devt, void *osbuf, WMI_PRI_STREAM_ID streamID)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+ A_STATUS status = A_OK;
+ struct ar_cookie *cookie = NULL;
+ int i;
+
+ /* take lock to protect ar6000_alloc_cookie() */
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+
+ do {
+
+ AR_DEBUG2_PRINTF("ar_contrstatus = ol_tx: skb=0x%x, len=0x%x, sid=%d\n",
+ (A_UINT32)osbuf, A_NETBUF_LEN(osbuf), streamID);
+
+ if ((streamID == WMI_CONTROL_PRI) && (ar->arWMIControlEpFull)) {
+ /* control endpoint is full, don't allocate resources, we
+ * are just going to drop this packet */
+ cookie = NULL;
+ AR_DEBUG_PRINTF(" WMI Control EP full, dropping packet : 0x%X, len:%d \n",
+ (A_UINT32)osbuf, A_NETBUF_LEN(osbuf));
+ } else {
+ cookie = ar6000_alloc_cookie(ar);
+ }
+
+ if (cookie == NULL) {
+ status = A_NO_MEMORY;
+ break;
+ }
+
+ if(logWmiRawMsgs) {
+ A_PRINTF("WMI cmd send, msgNo %d :", wmiSendCmdNum);
+ for(i = 0; i < a_netbuf_to_len(osbuf); i++)
+ A_PRINTF("%x ", ((A_UINT8 *)a_netbuf_to_data(osbuf))[i]);
+ A_PRINTF("\n");
+ }
+
+ wmiSendCmdNum++;
+
+ } while (FALSE);
+
+ if (cookie != NULL) {
+ /* got a structure to send it out on */
+ ar->arTxPending[streamID]++;
+
+ if (streamID != WMI_CONTROL_PRI) {
+ ar->arTotalTxDataPending++;
+ }
+ }
+
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+
+ if (cookie != NULL) {
+ cookie->arc_bp[0] = (A_UINT32)osbuf;
+ cookie->arc_bp[1] = 0;
+ SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
+ cookie,
+ A_NETBUF_DATA(osbuf),
+ A_NETBUF_LEN(osbuf),
+ arWMIStream2EndpointID(ar,streamID),
+ AR6K_CONTROL_PKT_TAG);
+ /* this interface is asynchronous, if there is an error, cleanup will happen in the
+ * TX completion callback */
+ HTCSendPkt(ar->arHtcTarget, &cookie->HtcPkt);
+ status = A_OK;
+ }
+
+ return status;
+}
+
+/* indicate tx activity or inactivity on a WMI stream */
+void ar6000_indicate_tx_activity(void *devt, A_UINT8 TrafficClass, A_BOOL Active)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+ WMI_PRI_STREAM_ID streamid;
+
+ if (ar->arWmiEnabled) {
+ streamid = wmi_get_stream_id(ar->arWmi, TrafficClass);
+ } else {
+ /* for mbox ping testing, the traffic class is mapped directly as a stream ID,
+ * see handling of AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE in ioctl.c */
+ streamid = (WMI_PRI_STREAM_ID)TrafficClass;
+ }
+
+ /* notify HTC, this may cause credit distribution changes */
+
+ HTCIndicateActivityChange(ar->arHtcTarget,
+ arWMIStream2EndpointID(ar,streamid),
+ Active);
+
+}
+
+module_init(ar6000_init_module);
+module_exit(ar6000_cleanup_module);
+
+/* Init cookie queue */
+static void
+ar6000_cookie_init(AR_SOFTC_T *ar)
+{
+ A_UINT32 i;
+
+ ar->arCookieList = NULL;
+ A_MEMZERO(s_ar_cookie_mem, sizeof(s_ar_cookie_mem));
+
+ for (i = 0; i < MAX_COOKIE_NUM; i++) {
+ ar6000_free_cookie(ar, &s_ar_cookie_mem[i]);
+ }
+}
+
+/* cleanup cookie queue */
+static void
+ar6000_cookie_cleanup(AR_SOFTC_T *ar)
+{
+ /* It is gone .... */
+ ar->arCookieList = NULL;
+}
+
+/* Init cookie queue */
+static void
+ar6000_free_cookie(AR_SOFTC_T *ar, struct ar_cookie * cookie)
+{
+ /* Insert first */
+ A_ASSERT(ar != NULL);
+ A_ASSERT(cookie != NULL);
+ cookie->arc_list_next = ar->arCookieList;
+ ar->arCookieList = cookie;
+}
+
+/* cleanup cookie queue */
+static struct ar_cookie *
+ar6000_alloc_cookie(AR_SOFTC_T *ar)
+{
+ struct ar_cookie *cookie;
+
+ cookie = ar->arCookieList;
+ if(cookie != NULL)
+ {
+ ar->arCookieList = cookie->arc_list_next;
+ }
+
+ return cookie;
+}
+
+#ifdef SEND_EVENT_TO_APP
+/*
+ * This function is used to send event which come from taget to
+ * the application. The buf which send to application is include
+ * the event ID and event content.
+ */
+#define EVENT_ID_LEN 2
+void ar6000_send_event_to_app(AR_SOFTC_T *ar, A_UINT16 eventId,
+ A_UINT8 *datap, int len)
+{
+
+#if (WIRELESS_EXT >= 15)
+
+/* note: IWEVCUSTOM only exists in wireless extensions after version 15 */
+
+ char *buf;
+ A_UINT16 size;
+ union iwreq_data wrqu;
+
+ size = len + EVENT_ID_LEN;
+
+ if (size > IW_CUSTOM_MAX) {
+ AR_DEBUG_PRINTF("WMI event ID : 0x%4.4X, len = %d too big for IWEVCUSTOM (max=%d) \n",
+ eventId, size, IW_CUSTOM_MAX);
+ return;
+ }
+
+ buf = A_MALLOC_NOWAIT(size);
+ A_MEMZERO(buf, size);
+ A_MEMCPY(buf, &eventId, EVENT_ID_LEN);
+ A_MEMCPY(buf+EVENT_ID_LEN, datap, len);
+
+ //AR_DEBUG_PRINTF("event ID = %d,len = %d\n",*(A_UINT16*)buf, size);
+ A_MEMZERO(&wrqu, sizeof(wrqu));
+ wrqu.data.length = size;
+ wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
+
+ A_FREE(buf);
+#endif
+
+
+}
+#endif
+
+
+void
+ar6000_tx_retry_err_event(void *devt)
+{
+ AR_DEBUG2_PRINTF("Tx retries reach maximum!\n");
+}
+
+void
+ar6000_snrThresholdEvent_rx(void *devt, WMI_SNR_THRESHOLD_VAL newThreshold, A_UINT8 snr)
+{
+ AR_DEBUG2_PRINTF("snr threshold range %d, snr %d\n", newThreshold, snr);
+}
+
+void
+ar6000_lqThresholdEvent_rx(void *devt, WMI_LQ_THRESHOLD_VAL newThreshold, A_UINT8 lq)
+{
+ AR_DEBUG2_PRINTF("lq threshold range %d, lq %d\n", newThreshold, lq);
+}
+
+
+
+A_UINT32
+a_copy_to_user(void *to, const void *from, A_UINT32 n)
+{
+ return(copy_to_user(to, from, n));
+}
+
+A_UINT32
+a_copy_from_user(void *to, const void *from, A_UINT32 n)
+{
+ return(copy_from_user(to, from, n));
+}
+
+
+A_STATUS
+ar6000_get_driver_cfg(struct net_device *dev,
+ A_UINT16 cfgParam,
+ void *result)
+{
+
+ A_STATUS ret = 0;
+
+ switch(cfgParam)
+ {
+ case AR6000_DRIVER_CFG_GET_WLANNODECACHING:
+ *((A_UINT32 *)result) = wlanNodeCaching;
+ break;
+ case AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS:
+ *((A_UINT32 *)result) = logWmiRawMsgs;
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+void
+ar6000_keepalive_rx(void *devt, A_UINT8 configured)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+
+ ar->arKeepaliveConfigured = configured;
+ wake_up(&arEvent);
+}
+
+void
+ar6000_pmkid_list_event(void *devt, A_UINT8 numPMKID, WMI_PMKID *pmkidList)
+{
+ A_UINT8 i, j;
+
+ A_PRINTF("Number of Cached PMKIDs is %d\n", numPMKID);
+
+ for (i = 0; i < numPMKID; i++) {
+ A_PRINTF("\nPMKID %d ", i);
+ for (j = 0; j < WMI_PMKID_LEN; j++) {
+ A_PRINTF("%2.2x", pmkidList->pmkid[j]);
+ }
+ pmkidList++;
+ }
+}
+
+#ifdef USER_KEYS
+static A_STATUS
+
+ar6000_reinstall_keys(AR_SOFTC_T *ar, A_UINT8 key_op_ctrl)
+{
+ A_STATUS status = A_OK;
+ struct ieee80211req_key *uik = &ar->user_saved_keys.ucast_ik;
+ struct ieee80211req_key *bik = &ar->user_saved_keys.bcast_ik;
+ CRYPTO_TYPE keyType = ar->user_saved_keys.keyType;
+
+ if (IEEE80211_CIPHER_CCKM_KRK != uik->ik_type) {
+ if (NONE_CRYPT == keyType) {
+ goto _reinstall_keys_out;
+ }
+
+ if (uik->ik_keylen) {
+ status = wmi_addKey_cmd(ar->arWmi, uik->ik_keyix,
+ ar->user_saved_keys.keyType, PAIRWISE_USAGE,
+ uik->ik_keylen, (A_UINT8 *)&uik->ik_keyrsc,
+ uik->ik_keydata, key_op_ctrl, SYNC_BEFORE_WMIFLAG);
+ }
+
+ } else {
+ status = wmi_add_krk_cmd(ar->arWmi, uik->ik_keydata);
+ }
+
+ if (IEEE80211_CIPHER_CCKM_KRK != bik->ik_type) {
+ if (NONE_CRYPT == keyType) {
+ goto _reinstall_keys_out;
+ }
+
+ if (bik->ik_keylen) {
+ status = wmi_addKey_cmd(ar->arWmi, bik->ik_keyix,
+ ar->user_saved_keys.keyType, GROUP_USAGE,
+ bik->ik_keylen, (A_UINT8 *)&bik->ik_keyrsc,
+ bik->ik_keydata, key_op_ctrl, NO_SYNC_WMIFLAG);
+ }
+ } else {
+ status = wmi_add_krk_cmd(ar->arWmi, bik->ik_keydata);
+ }
+
+_reinstall_keys_out:
+ ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
+ ar->user_key_ctrl = 0;
+
+ return status;
+}
+#endif /* USER_KEYS */
+
+
+void
+ar6000_dset_open_req(
+ void *context,
+ A_UINT32 id,
+ A_UINT32 targHandle,
+ A_UINT32 targReplyFn,
+ A_UINT32 targReplyArg)
+{
+}
+
+void
+ar6000_dset_close(
+ void *context,
+ A_UINT32 access_cookie)
+{
+ return;
+}
+
+void
+ar6000_dset_data_req(
+ void *context,
+ A_UINT32 accessCookie,
+ A_UINT32 offset,
+ A_UINT32 length,
+ A_UINT32 targBuf,
+ A_UINT32 targReplyFn,
+ A_UINT32 targReplyArg)
+{
+}
--- /dev/null
+/*
+ *
+ * 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_ */
--- /dev/null
+/*
+ *
+ * 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 */
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * $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_ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ *
+ * 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"
+
+static A_UINT8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static A_UINT8 null_mac[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+extern USER_RSSI_THOLD rssi_map[12];
+extern unsigned int wmitimeout;
+extern A_WAITQUEUE_HEAD arEvent;
+extern int tspecCompliance;
+extern int bmienable;
+extern int bypasswmi;
+
+static int
+ar6000_ioctl_get_roam_tbl(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if(wmi_get_roam_tbl_cmd(ar->arWmi) != A_OK) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+ar6000_ioctl_get_roam_data(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+
+ /* currently assume only roam times are required */
+ if(wmi_get_roam_data_cmd(ar->arWmi, ROAM_DATA_TIME) != A_OK) {
+ return -EIO;
+ }
+
+
+ return 0;
+}
+
+static int
+ar6000_ioctl_set_roam_ctrl(struct net_device *dev, char *userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_ROAM_CTRL_CMD cmd;
+ A_UINT8 size = sizeof(cmd);
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+
+ if (copy_from_user(&cmd, userdata, size)) {
+ return -EFAULT;
+ }
+
+ if (cmd.roamCtrlType == WMI_SET_HOST_BIAS) {
+ if (cmd.info.bssBiasInfo.numBss > 1) {
+ size += (cmd.info.bssBiasInfo.numBss - 1) * sizeof(WMI_BSS_BIAS);
+ }
+ }
+
+ if (copy_from_user(&cmd, userdata, size)) {
+ return -EFAULT;
+ }
+
+ if(wmi_set_roam_ctrl_cmd(ar->arWmi, &cmd, size) != A_OK) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+ar6000_ioctl_set_powersave_timers(struct net_device *dev, char *userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_POWERSAVE_TIMERS_POLICY_CMD cmd;
+ A_UINT8 size = sizeof(cmd);
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, userdata, size)) {
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&cmd, userdata, size)) {
+ return -EFAULT;
+ }
+
+ if(wmi_set_powersave_timers_cmd(ar->arWmi, &cmd, size) != A_OK) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+ar6000_ioctl_set_wmm(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_WMM_CMD cmd;
+ A_STATUS ret;
+
+ if ((dev->flags & IFF_UP) != IFF_UP) {
+ return -EIO;
+ }
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1),
+ sizeof(cmd)))
+ {
+ return -EFAULT;
+ }
+
+ if (cmd.status == WMI_WMM_ENABLED) {
+ ar->arWmmEnabled = TRUE;
+ } else {
+ ar->arWmmEnabled = FALSE;
+ }
+
+ ret = wmi_set_wmm_cmd(ar->arWmi, cmd.status);
+
+ switch (ret) {
+ case A_OK:
+ return 0;
+ case A_EBUSY :
+ return -EBUSY;
+ case A_NO_MEMORY:
+ return -ENOMEM;
+ case A_EINVAL:
+ default:
+ return -EFAULT;
+ }
+}
+
+static int
+ar6000_ioctl_set_txop(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_WMM_TXOP_CMD cmd;
+ A_STATUS ret;
+
+ if ((dev->flags & IFF_UP) != IFF_UP) {
+ return -EIO;
+ }
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, (char *)((unsigned int*)rq->ifr_data + 1),
+ sizeof(cmd)))
+ {
+ return -EFAULT;
+ }
+
+ ret = wmi_set_wmm_txop(ar->arWmi, cmd.txopEnable);
+
+ switch (ret) {
+ case A_OK:
+ return 0;
+ case A_EBUSY :
+ return -EBUSY;
+ case A_NO_MEMORY:
+ return -ENOMEM;
+ case A_EINVAL:
+ default:
+ return -EFAULT;
+ }
+}
+
+static int
+ar6000_ioctl_get_rd(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ A_STATUS ret = 0;
+
+ if ((dev->flags & IFF_UP) != IFF_UP || ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if(copy_to_user((char *)((unsigned int*)rq->ifr_data + 1),
+ &ar->arRegCode, sizeof(ar->arRegCode)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+
+/* Get power mode command */
+static int
+ar6000_ioctl_get_power_mode(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_POWER_MODE_CMD power_mode;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ power_mode.powerMode = wmi_get_power_mode_cmd(ar->arWmi);
+ if (copy_to_user(rq->ifr_data, &power_mode, sizeof(WMI_POWER_MODE_CMD))) {
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+
+static int
+ar6000_ioctl_set_channelParams(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_CHANNEL_PARAMS_CMD cmd, *cmdp;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (cmd.numChannels > 1) {
+ cmdp = A_MALLOC(130);
+ if (copy_from_user(cmdp, rq->ifr_data,
+ sizeof (*cmdp) +
+ ((cmd.numChannels - 1) * sizeof(A_UINT16))))
+ {
+ kfree(cmdp);
+ return -EFAULT;
+ }
+ } else {
+ cmdp = &cmd;
+ }
+
+ if ((ar->arPhyCapability == WMI_11G_CAPABILITY) &&
+ ((cmdp->phyMode == WMI_11A_MODE) || (cmdp->phyMode == WMI_11AG_MODE)))
+ {
+ ret = -EINVAL;
+ }
+
+ if (!ret &&
+ (wmi_set_channelParams_cmd(ar->arWmi, cmdp->scanParam, cmdp->phyMode,
+ cmdp->numChannels, cmdp->channelList)
+ != A_OK))
+ {
+ ret = -EIO;
+ }
+
+ if (cmd.numChannels > 1) {
+ kfree(cmdp);
+ }
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_set_snr_threshold(struct net_device *dev, struct ifreq *rq)
+{
+
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SNR_THRESHOLD_PARAMS_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if( wmi_set_snr_threshold_params(ar->arWmi, &cmd) != A_OK ) {
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_set_rssi_threshold(struct net_device *dev, struct ifreq *rq)
+{
+#define SWAP_THOLD(thold1, thold2) do { \
+ USER_RSSI_THOLD tmpThold; \
+ tmpThold.tag = thold1.tag; \
+ tmpThold.rssi = thold1.rssi; \
+ thold1.tag = thold2.tag; \
+ thold1.rssi = thold2.rssi; \
+ thold2.tag = tmpThold.tag; \
+ thold2.rssi = tmpThold.rssi; \
+} while (0)
+
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_RSSI_THRESHOLD_PARAMS_CMD cmd;
+ USER_RSSI_PARAMS rssiParams;
+ A_INT32 i, j;
+
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user((char *)&rssiParams, (char *)((unsigned int *)rq->ifr_data + 1), sizeof(USER_RSSI_PARAMS))) {
+ return -EFAULT;
+ }
+ cmd.weight = rssiParams.weight;
+ cmd.pollTime = rssiParams.pollTime;
+
+ A_MEMCPY(rssi_map, &rssiParams.tholds, sizeof(rssi_map));
+ /*
+ * only 6 elements, so use bubble sorting, in ascending order
+ */
+ for (i = 5; i > 0; i--) {
+ for (j = 0; j < i; j++) { /* above tholds */
+ if (rssi_map[j+1].rssi < rssi_map[j].rssi) {
+ SWAP_THOLD(rssi_map[j+1], rssi_map[j]);
+ } else if (rssi_map[j+1].rssi == rssi_map[j].rssi) {
+ return EFAULT;
+ }
+ }
+ }
+ for (i = 11; i > 6; i--) {
+ for (j = 6; j < i; j++) { /* below tholds */
+ if (rssi_map[j+1].rssi < rssi_map[j].rssi) {
+ SWAP_THOLD(rssi_map[j+1], rssi_map[j]);
+ } else if (rssi_map[j+1].rssi == rssi_map[j].rssi) {
+ return EFAULT;
+ }
+ }
+ }
+
+#ifdef DEBUG
+ for (i = 0; i < 12; i++) {
+ AR_DEBUG2_PRINTF("thold[%d].tag: %d, thold[%d].rssi: %d \n",
+ i, rssi_map[i].tag, i, rssi_map[i].rssi);
+ }
+#endif
+ cmd.thresholdAbove1_Val = rssi_map[0].rssi;
+ cmd.thresholdAbove2_Val = rssi_map[1].rssi;
+ cmd.thresholdAbove3_Val = rssi_map[2].rssi;
+ cmd.thresholdAbove4_Val = rssi_map[3].rssi;
+ cmd.thresholdAbove5_Val = rssi_map[4].rssi;
+ cmd.thresholdAbove6_Val = rssi_map[5].rssi;
+ cmd.thresholdBelow1_Val = rssi_map[6].rssi;
+ cmd.thresholdBelow2_Val = rssi_map[7].rssi;
+ cmd.thresholdBelow3_Val = rssi_map[8].rssi;
+ cmd.thresholdBelow4_Val = rssi_map[9].rssi;
+ cmd.thresholdBelow5_Val = rssi_map[10].rssi;
+ cmd.thresholdBelow6_Val = rssi_map[11].rssi;
+
+ if( wmi_set_rssi_threshold_params(ar->arWmi, &cmd) != A_OK ) {
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_set_lq_threshold(struct net_device *dev, struct ifreq *rq)
+{
+
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_LQ_THRESHOLD_PARAMS_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, (char *)((unsigned int *)rq->ifr_data + 1), sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if( wmi_set_lq_threshold_params(ar->arWmi, &cmd) != A_OK ) {
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+
+static int
+ar6000_ioctl_set_probedSsid(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_PROBED_SSID_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_probedSsid_cmd(ar->arWmi, cmd.entryIndex, cmd.flag, cmd.ssidLength,
+ cmd.ssid) != A_OK)
+ {
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_set_badAp(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_ADD_BAD_AP_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (cmd.badApIndex > WMI_MAX_BAD_AP_INDEX) {
+ return -EIO;
+ }
+
+ if (A_MEMCMP(cmd.bssid, null_mac, AR6000_ETH_ADDR_LEN) == 0) {
+ /*
+ * This is a delete badAP.
+ */
+ if (wmi_deleteBadAp_cmd(ar->arWmi, cmd.badApIndex) != A_OK) {
+ ret = -EIO;
+ }
+ } else {
+ if (wmi_addBadAp_cmd(ar->arWmi, cmd.badApIndex, cmd.bssid) != A_OK) {
+ ret = -EIO;
+ }
+ }
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_create_qos(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_CREATE_PSTREAM_CMD cmd;
+ A_STATUS ret;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ ret = wmi_verify_tspec_params(&cmd, tspecCompliance);
+ if (ret == A_OK)
+ ret = wmi_create_pstream_cmd(ar->arWmi, &cmd);
+
+ switch (ret) {
+ case A_OK:
+ return 0;
+ case A_EBUSY :
+ return -EBUSY;
+ case A_NO_MEMORY:
+ return -ENOMEM;
+ case A_EINVAL:
+ default:
+ return -EFAULT;
+ }
+}
+
+static int
+ar6000_ioctl_delete_qos(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_DELETE_PSTREAM_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ ret = wmi_delete_pstream_cmd(ar->arWmi, cmd.trafficClass, cmd.tsid);
+
+ switch (ret) {
+ case A_OK:
+ return 0;
+ case A_EBUSY :
+ return -EBUSY;
+ case A_NO_MEMORY:
+ return -ENOMEM;
+ case A_EINVAL:
+ default:
+ return -EFAULT;
+ }
+}
+
+static int
+ar6000_ioctl_get_qos_queue(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ struct ar6000_queuereq qreq;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if( copy_from_user(&qreq, rq->ifr_data,
+ sizeof(struct ar6000_queuereq)))
+ return -EFAULT;
+
+ qreq.activeTsids = wmi_get_mapped_qos_queue(ar->arWmi, qreq.trafficClass);
+
+ if (copy_to_user(rq->ifr_data, &qreq,
+ sizeof(struct ar6000_queuereq)))
+ {
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_HOST_TCMD_SUPPORT
+static A_STATUS
+ar6000_ioctl_tcmd_get_rx_report(struct net_device *dev,
+ struct ifreq *rq, A_UINT8 *data, A_UINT32 len)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ A_UINT32 buf[2];
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (down_interruptible(&ar->arSem)) {
+ return -ERESTARTSYS;
+ }
+ ar->tcmdRxReport = 0;
+ if (wmi_test_cmd(ar->arWmi, data, len) != A_OK) {
+ up(&ar->arSem);
+ return -EIO;
+ }
+
+ wait_event_interruptible_timeout(arEvent, ar->tcmdRxReport != 0, wmitimeout * HZ);
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ }
+
+ buf[0] = ar->tcmdRxTotalPkt;
+ buf[1] = ar->tcmdRxRssi;
+ if (!ret && copy_to_user(rq->ifr_data, buf, sizeof(buf))) {
+ ret = -EFAULT;
+ }
+
+ up(&ar->arSem);
+
+ return ret;
+}
+
+void
+ar6000_tcmd_rx_report_event(void *devt, A_UINT8 * results, int len)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)devt;
+ TCMD_CONT_RX * rx_rep = (TCMD_CONT_RX *)results;
+
+ ar->tcmdRxTotalPkt = rx_rep->u.report.totalPkt;
+ ar->tcmdRxRssi = rx_rep->u.report.rssiInDBm;
+ ar->tcmdRxReport = 1;
+
+ wake_up(&arEvent);
+}
+#endif /* CONFIG_HOST_TCMD_SUPPORT*/
+
+static int
+ar6000_ioctl_set_error_report_bitmask(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_TARGET_ERROR_REPORT_BITMASK cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ ret = wmi_set_error_report_bitmask(ar->arWmi, cmd.bitmask);
+
+ return (ret==0 ? ret : -EINVAL);
+}
+
+static int
+ar6000_clear_target_stats(struct net_device *dev)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ TARGET_STATS *pStats = &ar->arTargetStats;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+ AR6000_SPIN_LOCK(&ar->arLock, 0);
+ A_MEMZERO(pStats, sizeof(TARGET_STATS));
+ AR6000_SPIN_UNLOCK(&ar->arLock, 0);
+ return ret;
+}
+
+static int
+ar6000_ioctl_get_target_stats(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ TARGET_STATS_CMD cmd;
+ TARGET_STATS *pStats = &ar->arTargetStats;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+ if (down_interruptible(&ar->arSem)) {
+ return -ERESTARTSYS;
+ }
+
+ ar->statsUpdatePending = TRUE;
+
+ if(wmi_get_stats_cmd(ar->arWmi) != A_OK) {
+ up(&ar->arSem);
+ return -EIO;
+ }
+
+ wait_event_interruptible_timeout(arEvent, ar->statsUpdatePending == FALSE, wmitimeout * HZ);
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ }
+
+ if (!ret && copy_to_user(rq->ifr_data, pStats, sizeof(*pStats))) {
+ ret = -EFAULT;
+ }
+
+ if (cmd.clearStats == 1) {
+ ret = ar6000_clear_target_stats(dev);
+ }
+
+ up(&ar->arSem);
+
+ return ret;
+}
+
+static int
+ar6000_ioctl_set_access_params(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_ACCESS_PARAMS_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_set_access_params_cmd(ar->arWmi, cmd.txop, cmd.eCWmin, cmd.eCWmax,
+ cmd.aifsn) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+ar6000_ioctl_set_disconnect_timeout(struct net_device *dev, struct ifreq *rq)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_DISC_TIMEOUT_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, rq->ifr_data, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_disctimeout_cmd(ar->arWmi, cmd.disconnectTimeout) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+ar6000_xioctl_set_voice_pkt_size(struct net_device *dev, char * userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_VOICE_PKT_SIZE_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, userdata, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_set_voice_pkt_size_cmd(ar->arWmi, cmd.voicePktSize) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+
+ return (ret);
+}
+
+static int
+ar6000_xioctl_set_max_sp_len(struct net_device *dev, char * userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_MAX_SP_LEN_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, userdata, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_set_max_sp_len_cmd(ar->arWmi, cmd.maxSPLen) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return (ret);
+}
+
+
+static int
+ar6000_xioctl_set_bt_status_cmd(struct net_device *dev, char * userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_BT_STATUS_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, userdata, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_set_bt_status_cmd(ar->arWmi, cmd.streamType, cmd.status) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+ar6000_xioctl_set_bt_params_cmd(struct net_device *dev, char * userdata)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+ WMI_SET_BT_PARAMS_CMD cmd;
+ int ret = 0;
+
+ if (ar->arWmiReady == FALSE) {
+ return -EIO;
+ }
+
+ if (copy_from_user(&cmd, userdata, sizeof(cmd))) {
+ return -EFAULT;
+ }
+
+ if (wmi_set_bt_params_cmd(ar->arWmi, &cmd) == A_OK)
+ {
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return (ret);
+}
+
+#ifdef CONFIG_HOST_GPIO_SUPPORT
+struct ar6000_gpio_intr_wait_cmd_s gpio_intr_results;
+/* gpio_reg_results and gpio_data_available are protected by arSem */
+static struct ar6000_gpio_register_cmd_s gpio_reg_results;
+static A_BOOL gpio_data_available; /* Requested GPIO data available */
+static A_BOOL gpio_intr_available; /* GPIO interrupt info available */
+static A_BOOL gpio_ack_received; /* GPIO ack was received */
+
+/* Host-side initialization for General Purpose I/O support */
+void ar6000_gpio_init(void)
+{
+ gpio_intr_available = FALSE;
+ gpio_data_available = FALSE;
+ gpio_ack_received = FALSE;
+}
+
+/*
+ * Called when a GPIO interrupt is received from the Target.
+ * intr_values shows which GPIO pins have interrupted.
+ * input_values shows a recent value of GPIO pins.
+ */
+void
+ar6000_gpio_intr_rx(A_UINT32 intr_mask, A_UINT32 input_values)
+{
+ gpio_intr_results.intr_mask = intr_mask;
+ gpio_intr_results.input_values = input_values;
+ *((volatile A_BOOL *)&gpio_intr_available) = TRUE;
+ wake_up(&arEvent);
+}
+
+/*
+ * This is called when a response is received from the Target
+ * for a previous or ar6000_gpio_input_get or ar6000_gpio_register_get
+ * call.
+ */
+void
+ar6000_gpio_data_rx(A_UINT32 reg_id, A_UINT32 value)
+{
+ gpio_reg_results.gpioreg_id = reg_id;
+ gpio_reg_results.value = value;
+ *((volatile A_BOOL *)&gpio_data_available) = TRUE;
+ wake_up(&arEvent);
+}
+
+/*
+ * This is called when an acknowledgement is received from the Target
+ * for a previous or ar6000_gpio_output_set or ar6000_gpio_register_set
+ * call.
+ */
+void
+ar6000_gpio_ack_rx(void)
+{
+ gpio_ack_received = TRUE;
+ wake_up(&arEvent);
+}
+
+A_STATUS
+ar6000_gpio_output_set(struct net_device *dev,
+ A_UINT32 set_mask,
+ A_UINT32 clear_mask,
+ A_UINT32 enable_mask,
+ A_UINT32 disable_mask)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ gpio_ack_received = FALSE;
+ return wmi_gpio_output_set(ar->arWmi,
+ set_mask, clear_mask, enable_mask, disable_mask);
+}
+
+static A_STATUS
+ar6000_gpio_input_get(struct net_device *dev)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ *((volatile A_BOOL *)&gpio_data_available) = FALSE;
+ return wmi_gpio_input_get(ar->arWmi);
+}
+
+static A_STATUS
+ar6000_gpio_register_set(struct net_device *dev,
+ A_UINT32 gpioreg_id,
+ A_UINT32 value)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ gpio_ack_received = FALSE;
+ return wmi_gpio_register_set(ar->arWmi, gpioreg_id, value);
+}
+
+static A_STATUS
+ar6000_gpio_register_get(struct net_device *dev,
+ A_UINT32 gpioreg_id)
+{
+ AR_SOFTC_T *ar = (AR_SOFTC_T *)netdev_priv(dev);
+
+ *((volatile A_BOOL *)&gpio_data_available) = FALSE;
+