bump to 2.6.30-rc6

SVN-Revision: 15918
This commit is contained in:
Lars-Peter Clausen 2009-05-18 17:55:41 +00:00
parent 267af10b33
commit f5affd4f36
159 changed files with 55656 additions and 1 deletions

View file

@ -12,7 +12,7 @@ BOARDNAME:=Samsung S3C24xx
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

View file

@ -0,0 +1,253 @@
/*
* 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, &gta02_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, &gta02_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(&gta02_bt_driver);
}
static void gta02_bt_exit(void)
{
platform_driver_unregister(&gta02_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);

View file

@ -0,0 +1,244 @@
/*
* 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,
&gta02_gps_attr_group);
}
static int gta02_pm_gps_remove(struct platform_device *pdev)
{
regulator_put(gta02_gps.regulator);
sysfs_remove_group(&pdev->dev.kobj, &gta02_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(&gta02_pm_gps_driver);
}
static void gta02_pm_gps_exit(void)
{
platform_driver_unregister(&gta02_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>");

View file

@ -0,0 +1,275 @@
/*
* 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, &gta02_gsm_attr_group);
}
static int gta02_gsm_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &gta02_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(&gta02_gsm_driver);
}
static void gta02_gsm_exit(void)
{
platform_driver_unregister(&gta02_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");

View file

@ -0,0 +1,195 @@
/*
* 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(&gta02_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(&gta02_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(&gta02_wlan_rfkill_lock));
BUG_ON(gta02_wlan_rfkill_cb);
gta02_wlan_rfkill_cb = cb;
gta02_wlan_rfkill_user = user;
mutex_unlock(&gta02_wlan_rfkill_lock);
}
EXPORT_SYMBOL_GPL(gta02_wlan_set_rfkill_cb);
void gta02_wlan_clear_rfkill_cb(void)
{
mutex_lock(&gta02_wlan_rfkill_lock);
BUG_ON(!gta02_wlan_rfkill_cb);
gta02_wlan_rfkill_cb = NULL;
mutex_unlock(&gta02_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(&gta02_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(&gta02_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(&gta02_wlan_driver);
}
static void gta02_wlan_exit(void)
{
platform_driver_unregister(&gta02_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");

View file

@ -0,0 +1,86 @@
/*
* 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);

View file

@ -0,0 +1 @@
extern int gta02_pm_gps_is_on(void);

View file

@ -0,0 +1 @@
extern int gta_gsm_interrupts;

View file

@ -0,0 +1,10 @@
#ifndef __MACH_GTA02_PM_WLAN_H
#define __MACH_GTA02_PM_WLAN_H
void gta02_wlan_reset(int assert_reset);
int gta02_wlan_query_rfkill_lock(void);
void gta02_wlan_query_rfkill_unlock(void);
void gta02_wlan_set_rfkill_cb(int (*cb)(void *user, int on), void *user);
void gta02_wlan_clear_rfkill_cb(void);
#endif /* __MACH_GTA02_PM_WLAN_H */

View file

@ -0,0 +1,85 @@
#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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
config AR6000_WLAN
tristate "AR6000 wireless networking over SDIO"
depends on MMC
select WIRELESS_EXT
default m
help
good luck.
config AR6000_WLAN_DEBUG
bool "Enable retrieval of firmware debugging information"
depends on AR6000_WLAN
default n
help
The AR6k firmware maintains a log of debugging events that
gets flushed to the host on various occasions. Retrieval of
this data is very slow, taking several seconds.
If in doubt, say N.
config AR6000_WLAN_RESET
bool "Soft-reset when shutting down"
depends on AR6000_WLAN
default n
help
The AR6k module can be explicitly reset when shutting down
the device. This adds a delay of about two seconds to suspend,
module removal, and so on. Since the WLAN SDIO function is
generally disabled soon thereafter anyway, this reset seems
superfluous.
If in doubt, say N.

View file

@ -0,0 +1,38 @@
REV ?= 2
PWD := $(shell pwd)
EXTRA_CFLAGS += -I$(src)/include
EXTRA_CFLAGS += -DLINUX -D__KERNEL__ -DHTC_RAW_INTERFACE\
-DTCMD -DUSER_KEYS \
-DNO_SYNC_FLUSH #\
-DMULTIPLE_FRAMES_PER_INTERRUPT -DAR6000REV$(REV) \
-DBLOCK_TX_PATH_FLAG \
-DSDIO \
EXTRA_CFLAGS += -DKERNEL_2_6
obj-$(CONFIG_AR6000_WLAN) += ar6000.o
ar6000-objs += htc/ar6k.o \
htc/ar6k_events.o \
htc/htc_send.o \
htc/htc_recv.o \
htc/htc_services.o \
htc/htc.o \
hif/hif2.o \
bmi/bmi.o \
ar6000/ar6000_drv.o \
ar6000/ar6000_raw_if.o \
ar6000/netbuf.o \
ar6000/wireless_ext.o \
ar6000/ioctl.o \
miscdrv/common_drv.o \
miscdrv/credit_dist.o \
wmi/wmi.o \
wlan/wlan_node.o \
wlan/wlan_recv_beacon.o \
wlan/wlan_utils.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,360 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _AR6000_H_
#define _AR6000_H_
#include <linux/version.h>
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/semaphore.h>
#include <linux/wireless.h>
#include <linux/module.h>
#include <asm/io.h>
#include <a_config.h>
#include <athdefs.h>
#include "a_types.h"
#include "a_osapi.h"
#include "htc_api.h"
#include "wmi.h"
#include "a_drv.h"
#include "bmi.h"
#include <ieee80211.h>
#include <ieee80211_ioctl.h>
#include <wlan_api.h>
#include <wmi_api.h>
#include "gpio_api.h"
#include "gpio.h"
#include <host_version.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include "AR6Khwreg.h"
#include "ar6000_api.h"
#ifdef CONFIG_HOST_TCMD_SUPPORT
#include <testcmd.h>
#endif
#include "targaddrs.h"
#include "dbglog_api.h"
#include "ar6000_diag.h"
#include "common_drv.h"
#ifndef __dev_put
#define __dev_put(dev) dev_put(dev)
#endif
#ifdef USER_KEYS
#define USER_SAVEDKEYS_STAT_INIT 0
#define USER_SAVEDKEYS_STAT_RUN 1
// TODO this needs to move into the AR_SOFTC struct
struct USER_SAVEDKEYS {
struct ieee80211req_key ucast_ik;
struct ieee80211req_key bcast_ik;
CRYPTO_TYPE keyType;
A_BOOL keyOk;
};
#endif
#define DBG_INFO 0x00000001
#define DBG_ERROR 0x00000002
#define DBG_WARNING 0x00000004
#define DBG_SDIO 0x00000008
#define DBG_HIF 0x00000010
#define DBG_HTC 0x00000020
#define DBG_WMI 0x00000040
#define DBG_WMI2 0x00000080
#define DBG_DRIVER 0x00000100
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
#ifdef DEBUG
#define AR_DEBUG_PRINTF(args...) if (debugdriver) A_PRINTF(args);
#define AR_DEBUG2_PRINTF(args...) if (debugdriver >= 2) A_PRINTF(args);
extern int debugdriver;
#else
#define AR_DEBUG_PRINTF(args...)
#define AR_DEBUG2_PRINTF(args...)
#endif
A_STATUS ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
A_STATUS ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_AR6000 1
#define AR6000_MAX_RX_BUFFERS 16
#define AR6000_BUFFER_SIZE 1664
#define AR6000_TX_TIMEOUT 10
#define AR6000_ETH_ADDR_LEN 6
#define AR6000_MAX_ENDPOINTS 4
#define MAX_NODE_NUM 15
#define MAX_COOKIE_NUM 150
#define AR6000_HB_CHALLENGE_RESP_FREQ_DEFAULT 1
#define AR6000_HB_CHALLENGE_RESP_MISS_THRES_DEFAULT 1
enum {
DRV_HB_CHALLENGE = 0,
APP_HB_CHALLENGE
};
/* HTC RAW streams */
typedef enum _HTC_RAW_STREAM_ID {
HTC_RAW_STREAM_NOT_MAPPED = -1,
HTC_RAW_STREAM_0 = 0,
HTC_RAW_STREAM_1 = 1,
HTC_RAW_STREAM_2 = 2,
HTC_RAW_STREAM_3 = 3,
HTC_RAW_STREAM_NUM_MAX
} HTC_RAW_STREAM_ID;
#define RAW_HTC_READ_BUFFERS_NUM 4
#define RAW_HTC_WRITE_BUFFERS_NUM 4
typedef struct {
int currPtr;
int length;
unsigned char data[AR6000_BUFFER_SIZE];
HTC_PACKET HTCPacket;
} raw_htc_buffer;
#ifdef CONFIG_HOST_TCMD_SUPPORT
/*
* add TCMD_MODE besides wmi and bypasswmi
* in TCMD_MODE, only few TCMD releated wmi commands
* counld be hanlder
*/
enum {
AR6000_WMI_MODE = 0,
AR6000_BYPASS_MODE,
AR6000_TCMD_MODE,
AR6000_WLAN_MODE
};
#endif /* CONFIG_HOST_TCMD_SUPPORT */
struct ar_wep_key {
A_UINT8 arKeyIndex;
A_UINT8 arKeyLen;
A_UINT8 arKey[64];
} ;
struct ar_node_mapping {
A_UINT8 macAddress[6];
A_UINT8 epId;
A_UINT8 txPending;
};
struct ar_cookie {
A_UINT32 arc_bp[2]; /* Must be first field */
HTC_PACKET HtcPkt; /* HTC packet wrapper */
struct ar_cookie *arc_list_next;
};
struct ar_hb_chlng_resp {
A_TIMER timer;
A_UINT32 frequency;
A_UINT32 seqNum;
A_BOOL outstanding;
A_UINT8 missCnt;
A_UINT8 missThres;
};
typedef struct ar6_softc {
struct net_device *arNetDev; /* net_device pointer */
void *arWmi;
int arTxPending[WMI_PRI_MAX_COUNT];
int arTotalTxDataPending;
A_UINT8 arNumDataEndPts;
A_BOOL arWmiEnabled;
A_BOOL arWmiReady;
A_BOOL arConnected;
A_BOOL arRadioSwitch;
HTC_HANDLE arHtcTarget;
void *arHifDevice;
spinlock_t arLock;
struct semaphore arSem;
int arRxBuffers[WMI_PRI_MAX_COUNT];
int arSsidLen;
u_char arSsid[32];
A_UINT8 arNetworkType;
A_UINT8 arDot11AuthMode;
A_UINT8 arAuthMode;
A_UINT8 arPairwiseCrypto;
A_UINT8 arPairwiseCryptoLen;
A_UINT8 arGroupCrypto;
A_UINT8 arGroupCryptoLen;
A_UINT8 arDefTxKeyIndex;
struct ar_wep_key arWepKeyList[WMI_MAX_KEY_INDEX + 1];
A_UINT8 arBssid[6];
A_UINT8 arReqBssid[6];
A_UINT16 arChannelHint;
A_UINT16 arBssChannel;
A_UINT16 arListenInterval;
struct ar6000_version arVersion;
A_UINT32 arTargetType;
A_INT8 arRssi;
A_UINT8 arTxPwr;
A_BOOL arTxPwrSet;
A_INT32 arBitRate;
struct net_device_stats arNetStats;
struct iw_statistics arIwStats;
A_INT8 arNumChannels;
A_UINT16 arChannelList[32];
A_UINT32 arRegCode;
A_BOOL statsUpdatePending;
TARGET_STATS arTargetStats;
A_INT8 arMaxRetries;
A_UINT8 arPhyCapability;
#ifdef CONFIG_HOST_TCMD_SUPPORT
A_UINT8 tcmdRxReport;
A_UINT32 tcmdRxTotalPkt;
A_INT32 tcmdRxRssi;
A_UINT32 tcmdPm;
A_UINT32 arTargetMode;
#endif
AR6000_WLAN_STATE arWlanState;
struct ar_node_mapping arNodeMap[MAX_NODE_NUM];
A_UINT8 arIbssPsEnable;
A_UINT8 arNodeNum;
A_UINT8 arNexEpId;
struct ar_cookie *arCookieList;
A_UINT16 arRateMask;
A_UINT8 arSkipScan;
A_UINT16 arBeaconInterval;
A_BOOL arConnectPending;
A_BOOL arWmmEnabled;
struct ar_hb_chlng_resp arHBChallengeResp;
A_UINT8 arKeepaliveConfigured;
A_UINT32 arMgmtFilter;
HTC_ENDPOINT_ID arWmi2EpMapping[WMI_PRI_MAX_COUNT];
WMI_PRI_STREAM_ID arEp2WmiMapping[ENDPOINT_MAX];
#ifdef HTC_RAW_INTERFACE
HTC_ENDPOINT_ID arRaw2EpMapping[HTC_RAW_STREAM_NUM_MAX];
HTC_RAW_STREAM_ID arEp2RawMapping[ENDPOINT_MAX];
struct semaphore raw_htc_read_sem[HTC_RAW_STREAM_NUM_MAX];
struct semaphore raw_htc_write_sem[HTC_RAW_STREAM_NUM_MAX];
wait_queue_head_t raw_htc_read_queue[HTC_RAW_STREAM_NUM_MAX];
wait_queue_head_t raw_htc_write_queue[HTC_RAW_STREAM_NUM_MAX];
raw_htc_buffer *raw_htc_read_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_READ_BUFFERS_NUM];
raw_htc_buffer *raw_htc_write_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_WRITE_BUFFERS_NUM];
A_BOOL write_buffer_available[HTC_RAW_STREAM_NUM_MAX];
A_BOOL read_buffer_available[HTC_RAW_STREAM_NUM_MAX];
#endif
A_BOOL arRawIfInit;
int arDeviceIndex;
COMMON_CREDIT_STATE_INFO arCreditStateInfo;
A_BOOL arWMIControlEpFull;
A_BOOL dbgLogFetchInProgress;
A_UCHAR log_buffer[DBGLOG_HOST_LOG_BUFFER_SIZE];
A_UINT32 log_cnt;
A_UINT32 dbglog_init_done;
A_UINT32 arConnectCtrlFlags;
A_UINT32 scan_complete;
#ifdef USER_KEYS
A_INT32 user_savedkeys_stat;
A_UINT32 user_key_ctrl;
struct USER_SAVEDKEYS user_saved_keys;
#endif
} AR_SOFTC_T;
#define arWMIStream2EndpointID(ar,wmi) (ar)->arWmi2EpMapping[(wmi)]
#define arSetWMIStream2EndpointIDMap(ar,wmi,ep) \
{ (ar)->arWmi2EpMapping[(wmi)] = (ep); \
(ar)->arEp2WmiMapping[(ep)] = (wmi); }
#define arEndpoint2WMIStreamID(ar,ep) (ar)->arEp2WmiMapping[(ep)]
#define arRawIfEnabled(ar) (ar)->arRawIfInit
#define arRawStream2EndpointID(ar,raw) (ar)->arRaw2EpMapping[(raw)]
#define arSetRawStream2EndpointIDMap(ar,raw,ep) \
{ (ar)->arRaw2EpMapping[(raw)] = (ep); \
(ar)->arEp2RawMapping[(ep)] = (raw); }
#define arEndpoint2RawStreamID(ar,ep) (ar)->arEp2RawMapping[(ep)]
struct ar_giwscan_param {
char *current_ev;
char *end_buf;
A_BOOL firstPass;
};
#define AR6000_STAT_INC(ar, stat) (ar->arNetStats.stat++)
#define AR6000_SPIN_LOCK(lock, param) do { \
if (irqs_disabled()) { \
AR_DEBUG_PRINTF("IRQs disabled:AR6000_LOCK\n"); \
} \
spin_lock_bh(lock); \
} while (0)
#define AR6000_SPIN_UNLOCK(lock, param) do { \
if (irqs_disabled()) { \
AR_DEBUG_PRINTF("IRQs disabled: AR6000_UNLOCK\n"); \
} \
spin_unlock_bh(lock); \
} while (0)
int ar6000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
int ar6000_ioctl_dispatcher(struct net_device *dev, struct ifreq *rq, int cmd);
void ar6000_ioctl_iwsetup(struct iw_handler_def *def);
void ar6000_gpio_init(void);
void ar6000_init_profile_info(AR_SOFTC_T *ar);
void ar6000_install_static_wep_keys(AR_SOFTC_T *ar);
int ar6000_init(struct net_device *dev);
int ar6000_dbglog_get_debug_logs(AR_SOFTC_T *ar);
A_STATUS ar6000_SetHTCBlockSize(AR_SOFTC_T *ar);
#ifdef HTC_RAW_INTERFACE
#ifndef __user
#define __user
#endif
int ar6000_htc_raw_open(AR_SOFTC_T *ar);
int ar6000_htc_raw_close(AR_SOFTC_T *ar);
ssize_t ar6000_htc_raw_read(AR_SOFTC_T *ar,
HTC_RAW_STREAM_ID StreamID,
char __user *buffer, size_t count);
ssize_t ar6000_htc_raw_write(AR_SOFTC_T *ar,
HTC_RAW_STREAM_ID StreamID,
char __user *buffer, size_t count);
#endif /* HTC_RAW_INTERFACE */
#ifdef __cplusplus
}
#endif
#endif /* _AR6000_H_ */

View file

@ -0,0 +1,440 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "ar6000_drv.h"
#ifdef HTC_RAW_INTERFACE
static void
ar6000_htc_raw_read_cb(void *Context, HTC_PACKET *pPacket)
{
AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
raw_htc_buffer *busy;
HTC_RAW_STREAM_ID streamID;
busy = (raw_htc_buffer *)pPacket->pPktContext;
A_ASSERT(busy != NULL);
if (pPacket->Status == A_ECANCELED) {
/*
* HTC provides A_ECANCELED status when it doesn't want to be refilled
* (probably due to a shutdown)
*/
return;
}
streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
#ifdef CF
if (down_trylock(&ar->raw_htc_read_sem[streamID])) {
#else
if (down_interruptible(&ar->raw_htc_read_sem[streamID])) {
#endif /* CF */
AR_DEBUG2_PRINTF("Unable to down the semaphore\n");
}
A_ASSERT((pPacket->Status != A_OK) ||
(pPacket->pBuffer == (busy->data + HTC_HEADER_LEN)));
busy->length = pPacket->ActualLength + HTC_HEADER_LEN;
busy->currPtr = HTC_HEADER_LEN;
ar->read_buffer_available[streamID] = TRUE;
//AR_DEBUG_PRINTF("raw read cb: 0x%X 0x%X \n", busy->currPtr,busy->length);
up(&ar->raw_htc_read_sem[streamID]);
/* Signal the waiting process */
AR_DEBUG2_PRINTF("Waking up the StreamID(%d) read process\n", streamID);
wake_up_interruptible(&ar->raw_htc_read_queue[streamID]);
}
static void
ar6000_htc_raw_write_cb(void *Context, HTC_PACKET *pPacket)
{
AR_SOFTC_T *ar = (AR_SOFTC_T *)Context;
raw_htc_buffer *free;
HTC_RAW_STREAM_ID streamID;
free = (raw_htc_buffer *)pPacket->pPktContext;
A_ASSERT(free != NULL);
if (pPacket->Status == A_ECANCELED) {
/*
* HTC provides A_ECANCELED status when it doesn't want to be refilled
* (probably due to a shutdown)
*/
return;
}
streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
#ifdef CF
if (down_trylock(&ar->raw_htc_write_sem[streamID])) {
#else
if (down_interruptible(&ar->raw_htc_write_sem[streamID])) {
#endif
AR_DEBUG2_PRINTF("Unable to down the semaphore\n");
}
A_ASSERT(pPacket->pBuffer == (free->data + HTC_HEADER_LEN));
free->length = 0;
ar->write_buffer_available[streamID] = TRUE;
up(&ar->raw_htc_write_sem[streamID]);
/* Signal the waiting process */
AR_DEBUG2_PRINTF("Waking up the StreamID(%d) write process\n", streamID);
wake_up_interruptible(&ar->raw_htc_write_queue[streamID]);
}
/* connect to a service */
static A_STATUS ar6000_connect_raw_service(AR_SOFTC_T *ar,
HTC_RAW_STREAM_ID StreamID)
{
A_STATUS status;
HTC_SERVICE_CONNECT_RESP response;
A_UINT8 streamNo;
HTC_SERVICE_CONNECT_REQ connect;
do {
A_MEMZERO(&connect,sizeof(connect));
/* pass the stream ID as meta data to the RAW streams service */
streamNo = (A_UINT8)StreamID;
connect.pMetaData = &streamNo;
connect.MetaDataLength = sizeof(A_UINT8);
/* these fields are the same for all endpoints */
connect.EpCallbacks.pContext = ar;
connect.EpCallbacks.EpTxComplete = ar6000_htc_raw_write_cb;
connect.EpCallbacks.EpRecv = ar6000_htc_raw_read_cb;
/* simple interface, we don't need these optional callbacks */
connect.EpCallbacks.EpRecvRefill = NULL;
connect.EpCallbacks.EpSendFull = NULL;
connect.EpCallbacks.EpSendAvail = NULL;
connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM;
/* connect to the raw streams service, we may be able to get 1 or more
* connections, depending on WHAT is running on the target */
connect.ServiceID = HTC_RAW_STREAMS_SVC;
A_MEMZERO(&response,sizeof(response));
/* try to connect to the raw stream, it is okay if this fails with
* status HTC_SERVICE_NO_MORE_EP */
status = HTCConnectService(ar->arHtcTarget,
&connect,
&response);
if (A_FAILED(status)) {
if (response.ConnectRespCode == HTC_SERVICE_NO_MORE_EP) {
AR_DEBUG_PRINTF("HTC RAW , No more streams allowed \n");
status = A_OK;
}
break;
}
/* set endpoint mapping for the RAW HTC streams */
arSetRawStream2EndpointIDMap(ar,StreamID,response.Endpoint);
AR_DEBUG_PRINTF("HTC RAW : stream ID: %d, endpoint: %d\n",
StreamID, arRawStream2EndpointID(ar,StreamID));
} while (FALSE);
return status;
}
int ar6000_htc_raw_open(AR_SOFTC_T *ar)
{
A_STATUS status;
int streamID, endPt, count2;
raw_htc_buffer *buffer;
HTC_SERVICE_ID servicepriority;
A_ASSERT(ar->arHtcTarget != NULL);
/* wait for target */
status = HTCWaitTarget(ar->arHtcTarget);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF("HTCWaitTarget failed (%d)\n", status);
return -ENODEV;
}
for (endPt = 0; endPt < ENDPOINT_MAX; endPt++) {
ar->arEp2RawMapping[endPt] = HTC_RAW_STREAM_NOT_MAPPED;
}
for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
/* Initialize the data structures */
init_MUTEX(&ar->raw_htc_read_sem[streamID]);
init_MUTEX(&ar->raw_htc_write_sem[streamID]);
init_waitqueue_head(&ar->raw_htc_read_queue[streamID]);
init_waitqueue_head(&ar->raw_htc_write_queue[streamID]);
/* try to connect to the raw service */
status = ar6000_connect_raw_service(ar,streamID);
if (A_FAILED(status)) {
break;
}
if (arRawStream2EndpointID(ar,streamID) == 0) {
break;
}
for (count2 = 0; count2 < RAW_HTC_READ_BUFFERS_NUM; count2 ++) {
/* Initialize the receive buffers */
buffer = ar->raw_htc_write_buffer[streamID][count2];
memset(buffer, 0, sizeof(raw_htc_buffer));
buffer = ar->raw_htc_read_buffer[streamID][count2];
memset(buffer, 0, sizeof(raw_htc_buffer));
SET_HTC_PACKET_INFO_RX_REFILL(&buffer->HTCPacket,
buffer,
buffer->data,
AR6000_BUFFER_SIZE,
arRawStream2EndpointID(ar,streamID));
/* Queue buffers to HTC for receive */
if ((status = HTCAddReceivePkt(ar->arHtcTarget, &buffer->HTCPacket)) != A_OK)
{
BMIInit();
return -EIO;
}
}
for (count2 = 0; count2 < RAW_HTC_WRITE_BUFFERS_NUM; count2 ++) {
/* Initialize the receive buffers */
buffer = ar->raw_htc_write_buffer[streamID][count2];
memset(buffer, 0, sizeof(raw_htc_buffer));
}
ar->read_buffer_available[streamID] = FALSE;
ar->write_buffer_available[streamID] = TRUE;
}
if (A_FAILED(status)) {
return -EIO;
}
AR_DEBUG_PRINTF("HTC RAW, number of streams the target supports: %d \n", streamID);
servicepriority = HTC_RAW_STREAMS_SVC; /* only 1 */
/* set callbacks and priority list */
HTCSetCreditDistribution(ar->arHtcTarget,
ar,
NULL, /* use default */
NULL, /* use default */
&servicepriority,
1);
/* Start the HTC component */
if ((status = HTCStart(ar->arHtcTarget)) != A_OK) {
BMIInit();
return -EIO;
}
(ar)->arRawIfInit = TRUE;
return 0;
}
int ar6000_htc_raw_close(AR_SOFTC_T *ar)
{
A_PRINTF("ar6000_htc_raw_close called \n");
HTCStop(ar->arHtcTarget);
/* reset the device */
ar6000_reset_device(ar->arHifDevice, ar->arTargetType);
/* Initialize the BMI component */
BMIInit();
return 0;
}
raw_htc_buffer *
get_filled_buffer(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID)
{
int count;
raw_htc_buffer *busy;
/* Check for data */
for (count = 0; count < RAW_HTC_READ_BUFFERS_NUM; count ++) {
busy = ar->raw_htc_read_buffer[StreamID][count];
if (busy->length) {
break;
}
}
if (busy->length) {
ar->read_buffer_available[StreamID] = TRUE;
} else {
ar->read_buffer_available[StreamID] = FALSE;
}
return busy;
}
ssize_t ar6000_htc_raw_read(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID,
char __user *buffer, size_t length)
{
int readPtr;
raw_htc_buffer *busy;
if (arRawStream2EndpointID(ar,StreamID) == 0) {
AR_DEBUG_PRINTF("StreamID(%d) not connected! \n", StreamID);
return -EFAULT;
}
if (down_interruptible(&ar->raw_htc_read_sem[StreamID])) {
return -ERESTARTSYS;
}
busy = get_filled_buffer(ar,StreamID);
while (!ar->read_buffer_available[StreamID]) {
up(&ar->raw_htc_read_sem[StreamID]);
/* Wait for the data */
AR_DEBUG2_PRINTF("Sleeping StreamID(%d) read process\n", StreamID);
if (wait_event_interruptible(ar->raw_htc_read_queue[StreamID],
ar->read_buffer_available[StreamID]))
{
return -EINTR;
}
if (down_interruptible(&ar->raw_htc_read_sem[StreamID])) {
return -ERESTARTSYS;
}
busy = get_filled_buffer(ar,StreamID);
}
/* Read the data */
readPtr = busy->currPtr;
if (length > busy->length - HTC_HEADER_LEN) {
length = busy->length - HTC_HEADER_LEN;
}
if (copy_to_user(buffer, &busy->data[readPtr], length)) {
up(&ar->raw_htc_read_sem[StreamID]);
return -EFAULT;
}
busy->currPtr += length;
//AR_DEBUG_PRINTF("raw read ioctl: currPTR : 0x%X 0x%X \n", busy->currPtr,busy->length);
if (busy->currPtr == busy->length)
{
busy->currPtr = 0;
busy->length = 0;
HTC_PACKET_RESET_RX(&busy->HTCPacket);
//AR_DEBUG_PRINTF("raw read ioctl: ep for packet:%d \n", busy->HTCPacket.Endpoint);
HTCAddReceivePkt(ar->arHtcTarget, &busy->HTCPacket);
}
ar->read_buffer_available[StreamID] = FALSE;
up(&ar->raw_htc_read_sem[StreamID]);
return length;
}
static raw_htc_buffer *
get_free_buffer(AR_SOFTC_T *ar, HTC_ENDPOINT_ID StreamID)
{
int count;
raw_htc_buffer *free;
free = NULL;
for (count = 0; count < RAW_HTC_WRITE_BUFFERS_NUM; count ++) {
free = ar->raw_htc_write_buffer[StreamID][count];
if (free->length == 0) {
break;
}
}
if (!free->length) {
ar->write_buffer_available[StreamID] = TRUE;
} else {
ar->write_buffer_available[StreamID] = FALSE;
}
return free;
}
ssize_t ar6000_htc_raw_write(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID,
char __user *buffer, size_t length)
{
int writePtr;
raw_htc_buffer *free;
if (arRawStream2EndpointID(ar,StreamID) == 0) {
AR_DEBUG_PRINTF("StreamID(%d) not connected! \n", StreamID);
return -EFAULT;
}
if (down_interruptible(&ar->raw_htc_write_sem[StreamID])) {
return -ERESTARTSYS;
}
/* Search for a free buffer */
free = get_free_buffer(ar,StreamID);
/* Check if there is space to write else wait */
while (!ar->write_buffer_available[StreamID]) {
up(&ar->raw_htc_write_sem[StreamID]);
/* Wait for buffer to become free */
AR_DEBUG2_PRINTF("Sleeping StreamID(%d) write process\n", StreamID);
if (wait_event_interruptible(ar->raw_htc_write_queue[StreamID],
ar->write_buffer_available[StreamID]))
{
return -EINTR;
}
if (down_interruptible(&ar->raw_htc_write_sem[StreamID])) {
return -ERESTARTSYS;
}
free = get_free_buffer(ar,StreamID);
}
/* Send the data */
writePtr = HTC_HEADER_LEN;
if (length > (AR6000_BUFFER_SIZE - HTC_HEADER_LEN)) {
length = AR6000_BUFFER_SIZE - HTC_HEADER_LEN;
}
if (copy_from_user(&free->data[writePtr], buffer, length)) {
up(&ar->raw_htc_read_sem[StreamID]);
return -EFAULT;
}
free->length = length;
SET_HTC_PACKET_INFO_TX(&free->HTCPacket,
free,
&free->data[writePtr],
length,
arRawStream2EndpointID(ar,StreamID),
AR6K_DATA_PKT_TAG);
HTCSendPkt(ar->arHtcTarget,&free->HTCPacket);
ar->write_buffer_available[StreamID] = FALSE;
up(&ar->raw_htc_write_sem[StreamID]);
return length;
}
#endif /* HTC_RAW_INTERFACE */

View file

@ -0,0 +1,128 @@
#ifndef _AR6XAPI_LINUX_H
#define _AR6XAPI_LINUX_H
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
struct ar6_softc;
void ar6000_ready_event(void *devt, A_UINT8 *datap, A_UINT8 phyCap);
A_UINT8 ar6000_iptos_to_userPriority(A_UINT8 *pkt);
A_STATUS ar6000_control_tx(void *devt, void *osbuf, WMI_PRI_STREAM_ID streamID);
void ar6000_connect_event(struct ar6_softc *ar, A_UINT16 channel,
A_UINT8 *bssid, A_UINT16 listenInterval,
A_UINT16 beaconInterval, NETWORK_TYPE networkType,
A_UINT8 beaconIeLen, A_UINT8 assocReqLen,
A_UINT8 assocRespLen,A_UINT8 *assocInfo);
void ar6000_disconnect_event(struct ar6_softc *ar, A_UINT8 reason,
A_UINT8 *bssid, A_UINT8 assocRespLen,
A_UINT8 *assocInfo, A_UINT16 protocolReasonStatus);
void ar6000_tkip_micerr_event(struct ar6_softc *ar, A_UINT8 keyid,
A_BOOL ismcast);
void ar6000_bitrate_rx(void *devt, A_INT32 rateKbps);
void ar6000_channelList_rx(void *devt, A_INT8 numChan, A_UINT16 *chanList);
void ar6000_regDomain_event(struct ar6_softc *ar, A_UINT32 regCode);
void ar6000_txPwr_rx(void *devt, A_UINT8 txPwr);
void ar6000_keepalive_rx(void *devt, A_UINT8 configured);
void ar6000_neighborReport_event(struct ar6_softc *ar, int numAps,
WMI_NEIGHBOR_INFO *info);
void ar6000_set_numdataendpts(struct ar6_softc *ar, A_UINT32 num);
void ar6000_scanComplete_event(struct ar6_softc *ar, A_STATUS status);
void ar6000_targetStats_event(struct ar6_softc *ar, WMI_TARGET_STATS *pStats);
void ar6000_rssiThreshold_event(struct ar6_softc *ar,
WMI_RSSI_THRESHOLD_VAL newThreshold,
A_INT16 rssi);
void ar6000_reportError_event(struct ar6_softc *, WMI_TARGET_ERROR_VAL errorVal);
void ar6000_cac_event(struct ar6_softc *ar, A_UINT8 ac, A_UINT8 cac_indication,
A_UINT8 statusCode, A_UINT8 *tspecSuggestion);
void ar6000_hbChallengeResp_event(struct ar6_softc *, A_UINT32 cookie, A_UINT32 source);
void
ar6000_roam_tbl_event(struct ar6_softc *ar, WMI_TARGET_ROAM_TBL *pTbl);
void
ar6000_roam_data_event(struct ar6_softc *ar, WMI_TARGET_ROAM_DATA *p);
void
ar6000_wow_list_event(struct ar6_softc *ar, A_UINT8 num_filters,
WMI_GET_WOW_LIST_REPLY *wow_reply);
void ar6000_pmkid_list_event(void *devt, A_UINT8 numPMKID,
WMI_PMKID *pmkidList);
void ar6000_gpio_intr_rx(A_UINT32 intr_mask, A_UINT32 input_values);
void ar6000_gpio_data_rx(A_UINT32 reg_id, A_UINT32 value);
void ar6000_gpio_ack_rx(void);
void ar6000_dbglog_init_done(struct ar6_softc *ar);
#ifdef SEND_EVENT_TO_APP
void ar6000_send_event_to_app(struct ar6_softc *ar, A_UINT16 eventId, A_UINT8 *datap, int len);
#endif
#ifdef CONFIG_HOST_TCMD_SUPPORT
void ar6000_tcmd_rx_report_event(void *devt, A_UINT8 * results, int len);
#endif
void ar6000_tx_retry_err_event(void *devt);
void ar6000_snrThresholdEvent_rx(void *devt,
WMI_SNR_THRESHOLD_VAL newThreshold,
A_UINT8 snr);
void ar6000_lqThresholdEvent_rx(void *devt, WMI_LQ_THRESHOLD_VAL range, A_UINT8 lqVal);
void ar6000_ratemask_rx(void *devt, A_UINT16 ratemask);
A_STATUS ar6000_get_driver_cfg(struct net_device *dev,
A_UINT16 cfgParam,
void *result);
void ar6000_bssInfo_event_rx(struct ar6_softc *ar, A_UINT8 *data, int len);
void ar6000_dbglog_event(struct ar6_softc *ar, A_UINT32 dropped,
A_INT8 *buffer, A_UINT32 length);
int ar6000_dbglog_get_debug_logs(struct ar6_softc *ar);
void ar6000_indicate_tx_activity(void *devt, A_UINT8 trafficClass, A_BOOL Active);
void ar6000_dset_open_req(void *devt,
A_UINT32 id,
A_UINT32 targ_handle,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg);
void ar6000_dset_close(void *devt, A_UINT32 access_cookie);
void ar6000_dset_data_req(void *devt,
A_UINT32 access_cookie,
A_UINT32 offset,
A_UINT32 length,
A_UINT32 targ_buf,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,993 @@
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _ATHDRV_LINUX_H
#define _ATHDRV_LINUX_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* There are two types of ioctl's here: Standard ioctls and
* eXtended ioctls. All extended ioctls (XIOCTL) are multiplexed
* off of the single ioctl command, AR6000_IOCTL_EXTENDED. The
* arguments for every XIOCTL starts with a 32-bit command word
* that is used to select which extended ioctl is in use. After
* the command word are command-specific arguments.
*/
/* Linux standard Wireless Extensions, private ioctl interfaces */
#define IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0)
#define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1)
#define IEEE80211_IOCTL_SETKEY (SIOCIWFIRSTPRIV+2)
#define IEEE80211_IOCTL_SETWMMPARAMS (SIOCIWFIRSTPRIV+3)
#define IEEE80211_IOCTL_DELKEY (SIOCIWFIRSTPRIV+4)
#define IEEE80211_IOCTL_GETWMMPARAMS (SIOCIWFIRSTPRIV+5)
#define IEEE80211_IOCTL_SETOPTIE (SIOCIWFIRSTPRIV+6)
#define IEEE80211_IOCTL_SETMLME (SIOCIWFIRSTPRIV+7)
//#define IEEE80211_IOCTL_GETOPTIE (SIOCIWFIRSTPRIV+7)
#define IEEE80211_IOCTL_ADDPMKID (SIOCIWFIRSTPRIV+8)
//#define IEEE80211_IOCTL_SETAUTHALG (SIOCIWFIRSTPRIV+10)
#define IEEE80211_IOCTL_LASTONE (SIOCIWFIRSTPRIV+9)
/* ====WMI Ioctls==== */
/*
*
* Many ioctls simply provide WMI services to application code:
* an application makes such an ioctl call with a set of arguments
* that are packaged into the corresponding WMI message, and sent
* to the Target.
*/
#define AR6000_IOCTL_WMI_GETREV (SIOCIWFIRSTPRIV+10)
/*
* arguments:
* ar6000_version *revision
*/
#define AR6000_IOCTL_WMI_SETPWR (SIOCIWFIRSTPRIV+11)
/*
* arguments:
* WMI_POWER_MODE_CMD pwrModeCmd (see include/wmi.h)
* uses: WMI_SET_POWER_MODE_CMDID
*/
#define AR6000_IOCTL_WMI_SETSCAN (SIOCIWFIRSTPRIV+12)
/*
* arguments:
* WMI_SCAN_PARAMS_CMD scanParams (see include/wmi.h)
* uses: WMI_SET_SCAN_PARAMS_CMDID
*/
#define AR6000_IOCTL_WMI_SETLISTENINT (SIOCIWFIRSTPRIV+13)
/*
* arguments:
* UINT32 listenInterval
* uses: WMI_SET_LISTEN_INT_CMDID
*/
#define AR6000_IOCTL_WMI_SETBSSFILTER (SIOCIWFIRSTPRIV+14)
/*
* arguments:
* WMI_BSS_FILTER filter (see include/wmi.h)
* uses: WMI_SET_BSS_FILTER_CMDID
*/
#define AR6000_IOCTL_WMI_SET_CHANNELPARAMS (SIOCIWFIRSTPRIV+16)
/*
* arguments:
* WMI_CHANNEL_PARAMS_CMD chParams
* uses: WMI_SET_CHANNEL_PARAMS_CMDID
*/
#define AR6000_IOCTL_WMI_SET_PROBEDSSID (SIOCIWFIRSTPRIV+17)
/*
* arguments:
* WMI_PROBED_SSID_CMD probedSsids (see include/wmi.h)
* uses: WMI_SETPROBED_SSID_CMDID
*/
#define AR6000_IOCTL_WMI_SET_PMPARAMS (SIOCIWFIRSTPRIV+18)
/*
* arguments:
* WMI_POWER_PARAMS_CMD powerParams (see include/wmi.h)
* uses: WMI_SET_POWER_PARAMS_CMDID
*/
#define AR6000_IOCTL_WMI_SET_BADAP (SIOCIWFIRSTPRIV+19)
/*
* arguments:
* WMI_ADD_BAD_AP_CMD badAPs (see include/wmi.h)
* uses: WMI_ADD_BAD_AP_CMDID
*/
#define AR6000_IOCTL_WMI_GET_QOS_QUEUE (SIOCIWFIRSTPRIV+20)
/*
* arguments:
* ar6000_queuereq queueRequest (see below)
*/
#define AR6000_IOCTL_WMI_CREATE_QOS (SIOCIWFIRSTPRIV+21)
/*
* arguments:
* WMI_CREATE_PSTREAM createPstreamCmd (see include/wmi.h)
* uses: WMI_CREATE_PSTREAM_CMDID
*/
#define AR6000_IOCTL_WMI_DELETE_QOS (SIOCIWFIRSTPRIV+22)
/*
* arguments:
* WMI_DELETE_PSTREAM_CMD deletePstreamCmd (see include/wmi.h)
* uses: WMI_DELETE_PSTREAM_CMDID
*/
#define AR6000_IOCTL_WMI_SET_SNRTHRESHOLD (SIOCIWFIRSTPRIV+23)
/*
* arguments:
* WMI_SNR_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
* uses: WMI_SNR_THRESHOLD_PARAMS_CMDID
*/
#define AR6000_IOCTL_WMI_SET_ERROR_REPORT_BITMASK (SIOCIWFIRSTPRIV+24)
/*
* arguments:
* WMI_TARGET_ERROR_REPORT_BITMASK errorReportBitMask (see include/wmi.h)
* uses: WMI_TARGET_ERROR_REPORT_BITMASK_CMDID
*/
#define AR6000_IOCTL_WMI_GET_TARGET_STATS (SIOCIWFIRSTPRIV+25)
/*
* arguments:
* TARGET_STATS *targetStats (see below)
* uses: WMI_GET_STATISTICS_CMDID
*/
#define AR6000_IOCTL_WMI_SET_ASSOC_INFO (SIOCIWFIRSTPRIV+26)
/*
* arguments:
* WMI_SET_ASSOC_INFO_CMD setAssocInfoCmd
* uses: WMI_SET_ASSOC_INFO_CMDID
*/
#define AR6000_IOCTL_WMI_SET_ACCESS_PARAMS (SIOCIWFIRSTPRIV+27)
/*
* arguments:
* WMI_SET_ACCESS_PARAMS_CMD setAccessParams (see include/wmi.h)
* uses: WMI_SET_ACCESS_PARAMS_CMDID
*/
#define AR6000_IOCTL_WMI_SET_BMISS_TIME (SIOCIWFIRSTPRIV+28)
/*
* arguments:
* UINT32 beaconMissTime
* uses: WMI_SET_BMISS_TIME_CMDID
*/
#define AR6000_IOCTL_WMI_SET_DISC_TIMEOUT (SIOCIWFIRSTPRIV+29)
/*
* arguments:
* WMI_DISC_TIMEOUT_CMD disconnectTimeoutCmd (see include/wmi.h)
* uses: WMI_SET_DISC_TIMEOUT_CMDID
*/
#define AR6000_IOCTL_WMI_SET_IBSS_PM_CAPS (SIOCIWFIRSTPRIV+30)
/*
* arguments:
* WMI_IBSS_PM_CAPS_CMD ibssPowerMgmtCapsCmd
* uses: WMI_SET_IBSS_PM_CAPS_CMDID
*/
/*
* There is a very small space available for driver-private
* wireless ioctls. In order to circumvent this limitation,
* we multiplex a bunch of ioctls (XIOCTLs) on top of a
* single AR6000_IOCTL_EXTENDED ioctl.
*/
#define AR6000_IOCTL_EXTENDED (SIOCIWFIRSTPRIV+31)
/* ====BMI Extended Ioctls==== */
#define AR6000_XIOCTL_BMI_DONE 1
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_BMI_DONE)
* uses: BMI_DONE
*/
#define AR6000_XIOCTL_BMI_READ_MEMORY 2
/*
* arguments:
* union {
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_READ_MEMORY)
* UINT32 address
* UINT32 length
* }
* char results[length]
* }
* uses: BMI_READ_MEMORY
*/
#define AR6000_XIOCTL_BMI_WRITE_MEMORY 3
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_MEMORY)
* UINT32 address
* UINT32 length
* char data[length]
* uses: BMI_WRITE_MEMORY
*/
#define AR6000_XIOCTL_BMI_EXECUTE 4
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_BMI_EXECUTE)
* UINT32 TargetAddress
* UINT32 parameter
* uses: BMI_EXECUTE
*/
#define AR6000_XIOCTL_BMI_SET_APP_START 5
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_BMI_SET_APP_START)
* UINT32 TargetAddress
* uses: BMI_SET_APP_START
*/
#define AR6000_XIOCTL_BMI_READ_SOC_REGISTER 6
/*
* arguments:
* union {
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_READ_SOC_REGISTER)
* UINT32 TargetAddress, 32-bit aligned
* }
* UINT32 result
* }
* uses: BMI_READ_SOC_REGISTER
*/
#define AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER 7
/*
* arguments:
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER)
* UINT32 TargetAddress, 32-bit aligned
* UINT32 newValue
* }
* uses: BMI_WRITE_SOC_REGISTER
*/
#define AR6000_XIOCTL_BMI_TEST 8
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_BMI_TEST)
* UINT32 address
* UINT32 length
* UINT32 count
*/
/* Historical Host-side DataSet support */
#define AR6000_XIOCTL_UNUSED9 9
#define AR6000_XIOCTL_UNUSED10 10
#define AR6000_XIOCTL_UNUSED11 11
/* ====Misc Extended Ioctls==== */
#define AR6000_XIOCTL_FORCE_TARGET_RESET 12
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_FORCE_TARGET_RESET)
*/
#ifdef HTC_RAW_INTERFACE
/* HTC Raw Interface Ioctls */
#define AR6000_XIOCTL_HTC_RAW_OPEN 13
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_OPEN)
*/
#define AR6000_XIOCTL_HTC_RAW_CLOSE 14
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_CLOSE)
*/
#define AR6000_XIOCTL_HTC_RAW_READ 15
/*
* arguments:
* union {
* struct {
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_READ)
* UINT32 mailboxID
* UINT32 length
* }
* results[length]
* }
*/
#define AR6000_XIOCTL_HTC_RAW_WRITE 16
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_HTC_RAW_WRITE)
* UINT32 mailboxID
* UINT32 length
* char buffer[length]
*/
#endif /* HTC_RAW_INTERFACE */
#define AR6000_XIOCTL_CHECK_TARGET_READY 17
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_CHECK_TARGET_READY)
*/
/* ====GPIO (General Purpose I/O) Extended Ioctls==== */
#define AR6000_XIOCTL_GPIO_OUTPUT_SET 18
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_OUTPUT_SET)
* ar6000_gpio_output_set_cmd_s (see below)
* uses: WMIX_GPIO_OUTPUT_SET_CMDID
*/
#define AR6000_XIOCTL_GPIO_INPUT_GET 19
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_INPUT_GET)
* uses: WMIX_GPIO_INPUT_GET_CMDID
*/
#define AR6000_XIOCTL_GPIO_REGISTER_SET 20
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_SET)
* ar6000_gpio_register_cmd_s (see below)
* uses: WMIX_GPIO_REGISTER_SET_CMDID
*/
#define AR6000_XIOCTL_GPIO_REGISTER_GET 21
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_GET)
* ar6000_gpio_register_cmd_s (see below)
* uses: WMIX_GPIO_REGISTER_GET_CMDID
*/
#define AR6000_XIOCTL_GPIO_INTR_ACK 22
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_ACK)
* ar6000_cpio_intr_ack_cmd_s (see below)
* uses: WMIX_GPIO_INTR_ACK_CMDID
*/
#define AR6000_XIOCTL_GPIO_INTR_WAIT 23
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_WAIT)
*/
/* ====more wireless commands==== */
#define AR6000_XIOCTL_SET_ADHOC_BSSID 24
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_SET_ADHOC_BSSID)
* WMI_SET_ADHOC_BSSID_CMD setAdHocBssidCmd (see include/wmi.h)
*/
#define AR6000_XIOCTL_SET_OPT_MODE 25
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_SET_OPT_MODE)
* WMI_SET_OPT_MODE_CMD setOptModeCmd (see include/wmi.h)
* uses: WMI_SET_OPT_MODE_CMDID
*/
#define AR6000_XIOCTL_OPT_SEND_FRAME 26
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_OPT_SEND_FRAME)
* WMI_OPT_TX_FRAME_CMD optTxFrameCmd (see include/wmi.h)
* uses: WMI_OPT_TX_FRAME_CMDID
*/
#define AR6000_XIOCTL_SET_ADHOC_BEACON_INTVAL 27
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_SET_ADHOC_BEACON_INTVAL)
* WMI_BEACON_INT_CMD beaconIntCmd (see include/wmi.h)
* uses: WMI_SET_BEACON_INT_CMDID
*/
#define IEEE80211_IOCTL_SETAUTHALG 28
#define AR6000_XIOCTL_SET_VOICE_PKT_SIZE 29
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_SET_VOICE_PKT_SIZE)
* WMI_SET_VOICE_PKT_SIZE_CMD setVoicePktSizeCmd (see include/wmi.h)
* uses: WMI_SET_VOICE_PKT_SIZE_CMDID
*/
#define AR6000_XIOCTL_SET_MAX_SP 30
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_SET_MAX_SP)
* WMI_SET_MAX_SP_LEN_CMD maxSPLen(see include/wmi.h)
* uses: WMI_SET_MAX_SP_LEN_CMDID
*/
#define AR6000_XIOCTL_WMI_GET_ROAM_TBL 31
#define AR6000_XIOCTL_WMI_SET_ROAM_CTRL 32
#define AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS 33
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS)
* WMI_SET_POWERSAVE_TIMERS_CMD powerSaveTimers(see include/wmi.h)
* WMI_SET_POWERSAVE_TIMERS_CMDID
*/
#define AR6000_XIOCTRL_WMI_GET_POWER_MODE 34
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTRL_WMI_GET_POWER_MODE)
*/
#define AR6000_XIOCTRL_WMI_SET_WLAN_STATE 35
typedef enum {
WLAN_DISABLED,
WLAN_ENABLED
} AR6000_WLAN_STATE;
/*
* arguments:
* enable/disable
*/
#define AR6000_XIOCTL_WMI_GET_ROAM_DATA 36
#define AR6000_XIOCTL_WMI_SETRETRYLIMITS 37
/*
* arguments:
* WMI_SET_RETRY_LIMITS_CMD ibssSetRetryLimitsCmd
* uses: WMI_SET_RETRY_LIMITS_CMDID
*/
#ifdef CONFIG_HOST_TCMD_SUPPORT
/* ====extended commands for radio test ==== */
#define AR6000_XIOCTL_TCMD_CONT_TX 38
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_TX)
* WMI_TCMD_CONT_TX_CMD contTxCmd (see include/wmi.h)
* uses: WMI_TCMD_CONT_TX_CMDID
*/
#define AR6000_XIOCTL_TCMD_CONT_RX 39
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_RX)
* WMI_TCMD_CONT_RX_CMD rxCmd (see include/wmi.h)
* uses: WMI_TCMD_CONT_RX_CMDID
*/
#define AR6000_XIOCTL_TCMD_PM 40
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_TCMD_PM)
* WMI_TCMD_PM_CMD pmCmd (see include/wmi.h)
* uses: WMI_TCMD_PM_CMDID
*/
#endif /* CONFIG_HOST_TCMD_SUPPORT */
#define AR6000_XIOCTL_WMI_STARTSCAN 41
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_STARTSCAN)
* UINT8 scanType
* UINT8 scanConnected
* A_BOOL forceFgScan
* uses: WMI_START_SCAN_CMDID
*/
#define AR6000_XIOCTL_WMI_SETFIXRATES 42
#define AR6000_XIOCTL_WMI_GETFIXRATES 43
#define AR6000_XIOCTL_WMI_SET_RSSITHRESHOLD 44
/*
* arguments:
* WMI_RSSI_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
* uses: WMI_RSSI_THRESHOLD_PARAMS_CMDID
*/
#define AR6000_XIOCTL_WMI_CLR_RSSISNR 45
/*
* arguments:
* WMI_CLR_RSSISNR_CMD thresholdParams (see include/wmi.h)
* uses: WMI_CLR_RSSISNR_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_LQTHRESHOLD 46
/*
* arguments:
* WMI_LQ_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
* uses: WMI_LQ_THRESHOLD_PARAMS_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_RTS 47
/*
* arguments:
* WMI_SET_RTS_MODE_CMD (see include/wmi.h)
* uses: WMI_SET_RTS_MODE_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_LPREAMBLE 48
#define AR6000_XIOCTL_WMI_SET_AUTHMODE 49
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_AUTHMODE)
* UINT8 mode
* uses: WMI_SET_RECONNECT_AUTH_MODE_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_REASSOCMODE 50
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_WMM)
* UINT8 mode
* uses: WMI_SET_WMM_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_WMM 51
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS)
* UINT32 frequency
* UINT8 threshold
*/
#define AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS 52
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP)
* UINT32 cookie
*/
#define AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP 53
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_WMI_GET_RD)
* UINT32 regDomain
*/
#define AR6000_XIOCTL_WMI_GET_RD 54
#define AR6000_XIOCTL_DIAG_READ 55
#define AR6000_XIOCTL_DIAG_WRITE 56
/*
* arguments cmd (AR6000_XIOCTL_SET_TXOP)
* WMI_TXOP_CFG txopEnable
*/
#define AR6000_XIOCTL_WMI_SET_TXOP 57
#ifdef USER_KEYS
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_USER_SETKEYS)
* UINT32 keyOpCtrl
* uses AR6000_USER_SETKEYS_INFO
*/
#define AR6000_XIOCTL_USER_SETKEYS 58
#endif /* USER_KEYS */
#define AR6000_XIOCTL_WMI_SET_KEEPALIVE 59
/*
* arguments:
* UINT8 cmd (AR6000_XIOCTL_WMI_SET_KEEPALIVE)
* UINT8 keepaliveInterval
* uses: WMI_SET_KEEPALIVE_CMDID
*/
#define AR6000_XIOCTL_WMI_GET_KEEPALIVE 60
/*
* arguments:
* UINT8 cmd (AR6000_XIOCTL_WMI_GET_KEEPALIVE)
* UINT8 keepaliveInterval
* A_BOOL configured
* uses: WMI_GET_KEEPALIVE_CMDID
*/
/* ====ROM Patching Extended Ioctls==== */
#define AR6000_XIOCTL_BMI_ROMPATCH_INSTALL 61
/*
* arguments:
* union {
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_INSTALL)
* UINT32 ROM Address
* UINT32 RAM Address
* UINT32 number of bytes
* UINT32 activate? (0 or 1)
* }
* A_UINT32 resulting rompatch ID
* }
* uses: BMI_ROMPATCH_INSTALL
*/
#define AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL 62
/*
* arguments:
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL)
* UINT32 rompatch ID
* }
* uses: BMI_ROMPATCH_UNINSTALL
*/
#define AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE 63
/*
* arguments:
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE)
* UINT32 rompatch count
* UINT32 rompatch IDs[rompatch count]
* }
* uses: BMI_ROMPATCH_ACTIVATE
*/
#define AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE 64
/*
* arguments:
* struct {
* UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE)
* UINT32 rompatch count
* UINT32 rompatch IDs[rompatch count]
* }
* uses: BMI_ROMPATCH_DEACTIVATE
*/
#define AR6000_XIOCTL_WMI_SET_APPIE 65
/*
* arguments:
* struct {
* UINT32 cmd (AR6000_XIOCTL_WMI_SET_APPIE)
* UINT32 app_frmtype;
* UINT32 app_buflen;
* UINT8 app_buf[];
* }
*/
#define AR6000_XIOCTL_WMI_SET_MGMT_FRM_RX_FILTER 66
/*
* arguments:
* A_UINT32 filter_type;
*/
#define AR6000_XIOCTL_DBGLOG_CFG_MODULE 67
#define AR6000_XIOCTL_DBGLOG_GET_DEBUG_LOGS 68
#define AR6000_XIOCTL_WMI_SET_WSC_STATUS 70
/*
* arguments:
* A_UINT32 wsc_status;
* (WSC_REG_INACTIVE or WSC_REG_ACTIVE)
*/
/*
* arguments:
* struct {
* A_UINT8 streamType;
* A_UINT8 status;
* }
* uses: WMI_SET_BT_STATUS_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_BT_STATUS 71
/*
* arguments:
* struct {
* A_UINT8 paramType;
* union {
* A_UINT8 noSCOPkts;
* BT_PARAMS_A2DP a2dpParams;
* BT_COEX_REGS regs;
* };
* }
* uses: WMI_SET_BT_PARAM_CMDID
*/
#define AR6000_XIOCTL_WMI_SET_BT_PARAMS 72
#define AR6000_XIOCTL_WMI_SET_HOST_SLEEP_MODE 73
#define AR6000_XIOCTL_WMI_SET_WOW_MODE 74
#define AR6000_XIOCTL_WMI_GET_WOW_LIST 75
#define AR6000_XIOCTL_WMI_ADD_WOW_PATTERN 76
#define AR6000_XIOCTL_WMI_DEL_WOW_PATTERN 77
#define AR6000_XIOCTL_TARGET_INFO 78
/*
* arguments:
* UINT32 cmd (AR6000_XIOCTL_TARGET_INFO)
* A_UINT32 TargetVersion (returned)
* A_UINT32 TargetType (returned)
* (See also bmi_msg.h target_ver and target_type)
*/
#define AR6000_XIOCTL_DUMP_HTC_CREDIT_STATE 79
/*
* arguments:
* none
*/
#define AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE 80
/*
* This ioctl is used to emulate traffic activity
* timeouts. Activity/inactivity will trigger the driver
* to re-balance credits.
*
* arguments:
* ar6000_traffic_activity_change
*/
#define AR6000_XIOCTL_WMI_SET_CONNECT_CTRL_FLAGS 81
/*
* This ioctl is used to set the connect control flags
*
* arguments:
* A_UINT32 connectCtrlFlags
*/
#define AR6000_XIOCTL_WMI_SET_AKMP_PARAMS 82
/*
* This IOCTL sets any Authentication,Key Management and Protection
* related parameters. This is used along with the information set in
* Connect Command.
* Currently this enables Multiple PMKIDs to an AP.
*
* arguments:
* struct {
* A_UINT32 akmpInfo;
* }
* uses: WMI_SET_AKMP_PARAMS_CMD
*/
#define AR6000_XIOCTL_WMI_GET_PMKID_LIST 83
#define AR6000_XIOCTL_WMI_SET_PMKID_LIST 84
/*
* This IOCTL is used to set a list of PMKIDs. This list of
* PMKIDs is used in the [Re]AssocReq Frame. This list is used
* only if the MultiPMKID option is enabled via the
* AR6000_XIOCTL_WMI_SET_AKMP_PARAMS IOCTL.
*
* arguments:
* struct {
* A_UINT32 numPMKID;
* WMI_PMKID pmkidList[WMI_MAX_PMKID_CACHE];
* }
* uses: WMI_SET_PMKIDLIST_CMD
*/
/* Historical DSETPATCH support for INI patches */
#define AR6000_XIOCTL_UNUSED90 90
/* used by AR6000_IOCTL_WMI_GETREV */
struct ar6000_version {
A_UINT32 host_ver;
A_UINT32 target_ver;
};
/* used by AR6000_IOCTL_WMI_GET_QOS_QUEUE */
struct ar6000_queuereq {
A_UINT8 trafficClass;
A_UINT16 activeTsids;
};
/* used by AR6000_IOCTL_WMI_GET_TARGET_STATS */
typedef struct targetStats_t {
A_UINT64 tx_packets;
A_UINT64 tx_bytes;
A_UINT64 tx_unicast_pkts;
A_UINT64 tx_unicast_bytes;
A_UINT64 tx_multicast_pkts;
A_UINT64 tx_multicast_bytes;
A_UINT64 tx_broadcast_pkts;
A_UINT64 tx_broadcast_bytes;
A_UINT64 tx_rts_success_cnt;
A_UINT64 tx_packet_per_ac[4];
A_UINT64 tx_errors;
A_UINT64 tx_failed_cnt;
A_UINT64 tx_retry_cnt;
A_UINT64 tx_rts_fail_cnt;
A_INT32 tx_unicast_rate;
A_UINT64 rx_packets;
A_UINT64 rx_bytes;
A_UINT64 rx_unicast_pkts;
A_UINT64 rx_unicast_bytes;
A_UINT64 rx_multicast_pkts;
A_UINT64 rx_multicast_bytes;
A_UINT64 rx_broadcast_pkts;
A_UINT64 rx_broadcast_bytes;
A_UINT64 rx_fragment_pkt;
A_UINT64 rx_errors;
A_UINT64 rx_crcerr;
A_UINT64 rx_key_cache_miss;
A_UINT64 rx_decrypt_err;
A_UINT64 rx_duplicate_frames;
A_INT32 rx_unicast_rate;
A_UINT64 tkip_local_mic_failure;
A_UINT64 tkip_counter_measures_invoked;
A_UINT64 tkip_replays;
A_UINT64 tkip_format_errors;
A_UINT64 ccmp_format_errors;
A_UINT64 ccmp_replays;
A_UINT64 power_save_failure_cnt;
A_INT16 noise_floor_calibation;
A_UINT64 cs_bmiss_cnt;
A_UINT64 cs_lowRssi_cnt;
A_UINT64 cs_connect_cnt;
A_UINT64 cs_disconnect_cnt;
A_UINT8 cs_aveBeacon_snr;
A_INT16 cs_aveBeacon_rssi;
A_UINT8 cs_lastRoam_msec;
A_UINT8 cs_snr;
A_INT16 cs_rssi;
A_UINT32 lq_val;
A_UINT32 wow_num_pkts_dropped;
A_UINT8 wow_num_host_pkt_wakeups;
A_UINT8 wow_num_host_event_wakeups;
A_UINT16 wow_num_events_discarded;
}TARGET_STATS;
typedef struct targetStats_cmd_t {
TARGET_STATS targetStats;
int clearStats;
} TARGET_STATS_CMD;
/* used by AR6000_XIOCTL_USER_SETKEYS */
/*
* Setting this bit to 1 doesnot initialize the RSC on the firmware
*/
#define AR6000_XIOCTL_USER_SETKEYS_RSC_CTRL 1
#define AR6000_USER_SETKEYS_RSC_UNCHANGED 0x00000002
typedef struct {
A_UINT32 keyOpCtrl; /* Bit Map of Key Mgmt Ctrl Flags */
} AR6000_USER_SETKEYS_INFO;
/* used by AR6000_XIOCTL_GPIO_OUTPUT_SET */
struct ar6000_gpio_output_set_cmd_s {
A_UINT32 set_mask;
A_UINT32 clear_mask;
A_UINT32 enable_mask;
A_UINT32 disable_mask;
};
/*
* used by AR6000_XIOCTL_GPIO_REGISTER_GET and AR6000_XIOCTL_GPIO_REGISTER_SET
*/
struct ar6000_gpio_register_cmd_s {
A_UINT32 gpioreg_id;
A_UINT32 value;
};
/* used by AR6000_XIOCTL_GPIO_INTR_ACK */
struct ar6000_gpio_intr_ack_cmd_s {
A_UINT32 ack_mask;
};
/* used by AR6000_XIOCTL_GPIO_INTR_WAIT */
struct ar6000_gpio_intr_wait_cmd_s {
A_UINT32 intr_mask;
A_UINT32 input_values;
};
/* used by the AR6000_XIOCTL_DBGLOG_CFG_MODULE */
typedef struct ar6000_dbglog_module_config_s {
A_UINT32 valid;
A_UINT16 mmask;
A_UINT16 tsr;
A_BOOL rep;
A_UINT16 size;
} DBGLOG_MODULE_CONFIG;
typedef struct user_rssi_thold_t {
A_INT16 tag;
A_INT16 rssi;
} USER_RSSI_THOLD;
typedef struct user_rssi_params_t {
A_UINT8 weight;
A_UINT32 pollTime;
USER_RSSI_THOLD tholds[12];
} USER_RSSI_PARAMS;
/*
* Host driver may have some config parameters. Typically, these
* config params are one time config parameters. These could
* correspond to any of the underlying modules. Host driver exposes
* an api for the underlying modules to get this config.
*/
#define AR6000_DRIVER_CFG_BASE 0x8000
/* Should driver perform wlan node caching? */
#define AR6000_DRIVER_CFG_GET_WLANNODECACHING 0x8001
/*Should we log raw WMI msgs */
#define AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS 0x8002
/* used by AR6000_XIOCTL_DIAG_READ & AR6000_XIOCTL_DIAG_WRITE */
struct ar6000_diag_window_cmd_s {
unsigned int addr;
unsigned int value;
};
struct ar6000_traffic_activity_change {
A_UINT32 StreamID; /* stream ID to indicate activity change */
A_UINT32 Active; /* active (1) or inactive (0) */
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,47 @@
/*
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/athtypes_linux.h#1 $
*
* This file contains the definitions of the basic atheros data types.
* It is used to map the data types in atheros files to a platform specific
* type.
*
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _ATHTYPES_LINUX_H_
#define _ATHTYPES_LINUX_H_
#ifdef __KERNEL__
#include <linux/types.h>
#endif
typedef int8_t A_INT8;
typedef int16_t A_INT16;
typedef int32_t A_INT32;
typedef int64_t A_INT64;
typedef u_int8_t A_UINT8;
typedef u_int16_t A_UINT16;
typedef u_int32_t A_UINT32;
typedef u_int64_t A_UINT64;
typedef int A_BOOL;
typedef char A_CHAR;
typedef unsigned char A_UCHAR;
typedef unsigned long A_ATH_TIMER;
#endif /* _ATHTYPES_LINUX_H_ */

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _CONFIG_LINUX_H_
#define _CONFIG_LINUX_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Host-side GPIO support is optional.
* If run-time access to GPIO pins is not required, then
* this should be changed to #undef.
*/
#define CONFIG_HOST_GPIO_SUPPORT
/*
* Host side Test Command support
*/
#define CONFIG_HOST_TCMD_SUPPORT
#define USE_4BYTE_REGISTER_ACCESS
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _DEBUG_LINUX_H_
#define _DEBUG_LINUX_H_
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
extern A_UINT32 g_dbg_flags;
#define DBGFMT "%s() : "
#define DBGARG __func__
#define DBGFN A_PRINTF
/* ------- Debug related stuff ------- */
enum {
ATH_DEBUG_SEND = 0x0001,
ATH_DEBUG_RECV = 0x0002,
ATH_DEBUG_SYNC = 0x0004,
ATH_DEBUG_DUMP = 0x0008,
ATH_DEBUG_IRQ = 0x0010,
ATH_DEBUG_TRC = 0x0020,
ATH_DEBUG_WARN = 0x0040,
ATH_DEBUG_ERR = 0x0080,
ATH_LOG_INF = 0x0100,
ATH_DEBUG_BMI = 0x0110,
ATH_DEBUG_WMI = 0x0120,
ATH_DEBUG_HIF = 0x0140,
ATH_DEBUG_HTC = 0x0180,
ATH_DEBUG_WLAN = 0x1000,
ATH_LOG_ERR = 0x1010,
ATH_DEBUG_ANY = 0xFFFF,
};
#ifdef DEBUG
#define A_DPRINTF(f, a) \
if(g_dbg_flags & (f)) \
{ \
DBGFN a ; \
}
// TODO FIX usage of A_PRINTF!
#define AR_DEBUG_LVL_CHECK(lvl) (debughtc & (lvl))
#define AR_DEBUG_PRINTBUF(buffer, length, desc) do { \
if (debughtc & ATH_DEBUG_DUMP) { \
DebugDumpBytes(buffer, length,desc); \
} \
} while(0)
#define PRINTX_ARG(arg...) arg
#define AR_DEBUG_PRINTF(flags, args) do { \
if (debughtc & (flags)) { \
A_PRINTF(KERN_ALERT PRINTX_ARG args); \
} \
} while (0)
#define AR_DEBUG_ASSERT(test) do { \
if (!(test)) { \
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,#test)); \
} \
} while(0)
extern int debughtc;
#else
#define AR_DEBUG_PRINTF(flags, args)
#define AR_DEBUG_PRINTBUF(buffer, length, desc)
#define AR_DEBUG_ASSERT(test)
#define AR_DEBUG_LVL_CHECK(lvl) 0
#define A_DPRINTF(f, a)
#endif
#endif /* _DEBUG_LINUX_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,225 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <a_config.h>
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "htc_packet.h"
#define AR6000_DATA_OFFSET 64
void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt)
{
skb_queue_tail((struct sk_buff_head *) q, (struct sk_buff *) pkt);
}
void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt)
{
skb_queue_head((struct sk_buff_head *) q, (struct sk_buff *) pkt);
}
void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q)
{
return((void *) skb_dequeue((struct sk_buff_head *) q));
}
int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q)
{
return(skb_queue_len((struct sk_buff_head *) q));
}
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q)
{
return(skb_queue_empty((struct sk_buff_head *) q));
}
void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q)
{
skb_queue_head_init((struct sk_buff_head *) q);
}
void *
a_netbuf_alloc(int size)
{
struct sk_buff *skb;
skb = dev_alloc_skb(AR6000_DATA_OFFSET + sizeof(HTC_PACKET) + size);
skb_reserve(skb, AR6000_DATA_OFFSET + sizeof(HTC_PACKET));
return ((void *)skb);
}
/*
* Allocate an SKB w.o. any encapsulation requirement.
*/
void *
a_netbuf_alloc_raw(int size)
{
struct sk_buff *skb;
skb = dev_alloc_skb(size);
return ((void *)skb);
}
void
a_netbuf_free(void *bufPtr)
{
struct sk_buff *skb = (struct sk_buff *)bufPtr;
dev_kfree_skb(skb);
}
A_UINT32
a_netbuf_to_len(void *bufPtr)
{
return (((struct sk_buff *)bufPtr)->len);
}
void *
a_netbuf_to_data(void *bufPtr)
{
return (((struct sk_buff *)bufPtr)->data);
}
/*
* Add len # of bytes to the beginning of the network buffer
* pointed to by bufPtr
*/
A_STATUS
a_netbuf_push(void *bufPtr, A_INT32 len)
{
skb_push((struct sk_buff *)bufPtr, len);
return A_OK;
}
/*
* Add len # of bytes to the beginning of the network buffer
* pointed to by bufPtr and also fill with data
*/
A_STATUS
a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len)
{
skb_push((struct sk_buff *) bufPtr, len);
A_MEMCPY(((struct sk_buff *)bufPtr)->data, srcPtr, len);
return A_OK;
}
/*
* Add len # of bytes to the end of the network buffer
* pointed to by bufPtr
*/
A_STATUS
a_netbuf_put(void *bufPtr, A_INT32 len)
{
skb_put((struct sk_buff *)bufPtr, len);
return A_OK;
}
/*
* Add len # of bytes to the end of the network buffer
* pointed to by bufPtr and also fill with data
*/
A_STATUS
a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len)
{
char *start = ((struct sk_buff *)bufPtr)->data +
((struct sk_buff *)bufPtr)->len;
skb_put((struct sk_buff *)bufPtr, len);
A_MEMCPY(start, srcPtr, len);
return A_OK;
}
/*
* Trim the network buffer pointed to by bufPtr to len # of bytes
*/
A_STATUS
a_netbuf_setlen(void *bufPtr, A_INT32 len)
{
skb_trim((struct sk_buff *)bufPtr, len);
return A_OK;
}
/*
* Chop of len # of bytes from the end of the buffer.
*/
A_STATUS
a_netbuf_trim(void *bufPtr, A_INT32 len)
{
skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
return A_OK;
}
/*
* Chop of len # of bytes from the end of the buffer and return the data.
*/
A_STATUS
a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len)
{
char *start = ((struct sk_buff *)bufPtr)->data +
(((struct sk_buff *)bufPtr)->len - len);
A_MEMCPY(dstPtr, start, len);
skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
return A_OK;
}
/*
* Returns the number of bytes available to a a_netbuf_push()
*/
A_INT32
a_netbuf_headroom(void *bufPtr)
{
return (skb_headroom((struct sk_buff *)bufPtr));
}
/*
* Removes specified number of bytes from the beginning of the buffer
*/
A_STATUS
a_netbuf_pull(void *bufPtr, A_INT32 len)
{
skb_pull((struct sk_buff *)bufPtr, len);
return A_OK;
}
/*
* Removes specified number of bytes from the beginning of the buffer
* and return the data
*/
A_STATUS
a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len)
{
A_MEMCPY(dstPtr, ((struct sk_buff *)bufPtr)->data, len);
skb_pull((struct sk_buff *)bufPtr, len);
return A_OK;
}

View file

@ -0,0 +1,319 @@
/*
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/osapi_linux.h#1 $
*
* This file contains the definitions of the basic atheros data types.
* It is used to map the data types in atheros files to a platform specific
* type.
*
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _OSAPI_LINUX_H_
#define _OSAPI_LINUX_H_
#ifdef __KERNEL__
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/jiffies.h>
#endif
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/wait.h>
#ifdef KERNEL_2_4
#include <asm/arch/irq.h>
#include <asm/irq.h>
#endif
#ifdef __GNUC__
#define __ATTRIB_PACK __attribute__ ((packed))
#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
#define __ATTRIB_NORETURN __attribute__ ((noreturn))
#ifndef INLINE
#define INLINE __inline__
#endif
#else /* Not GCC */
#define __ATTRIB_PACK
#define __ATTRIB_PRINTF
#define __ATTRIB_NORETURN
#ifndef INLINE
#define INLINE __inline
#endif
#endif /* End __GNUC__ */
#define PREPACK
#define POSTPACK __ATTRIB_PACK
/*
* Endianes macros
*/
#define A_BE2CPU8(x) ntohb(x)
#define A_BE2CPU16(x) ntohs(x)
#define A_BE2CPU32(x) ntohl(x)
#define A_LE2CPU8(x) (x)
#define A_LE2CPU16(x) (x)
#define A_LE2CPU32(x) (x)
#define A_CPU2BE8(x) htonb(x)
#define A_CPU2BE16(x) htons(x)
#define A_CPU2BE32(x) htonl(x)
#define A_MEMCPY(dst, src, len) memcpy((A_UINT8 *)(dst), (src), (len))
#define A_MEMZERO(addr, len) memset(addr, 0, len)
#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len))
#define A_MALLOC(size) kmalloc((size), GFP_KERNEL)
#define A_MALLOC_NOWAIT(size) kmalloc((size), GFP_ATOMIC)
#define A_FREE(addr) kfree(addr)
#define A_PRINTF(args...) printk(args)
/* Mutual Exclusion */
typedef spinlock_t A_MUTEX_T;
#define A_MUTEX_INIT(mutex) spin_lock_init(mutex)
#define A_MUTEX_LOCK(mutex) spin_lock_bh(mutex)
#define A_MUTEX_UNLOCK(mutex) spin_unlock_bh(mutex)
#define A_IS_MUTEX_VALID(mutex) TRUE /* okay to return true, since A_MUTEX_DELETE does nothing */
#define A_MUTEX_DELETE(mutex) /* spin locks are not kernel resources so nothing to free.. */
/* Get current time in ms adding a constant offset (in ms) */
#define A_GET_MS(offset) \
(jiffies + ((offset) / 1000) * HZ)
/*
* Timer Functions
*/
#define A_MDELAY(msecs) mdelay(msecs)
typedef struct timer_list A_TIMER;
#define A_INIT_TIMER(pTimer, pFunction, pArg) do { \
init_timer(pTimer); \
(pTimer)->function = (pFunction); \
(pTimer)->data = (unsigned long)(pArg); \
} while (0)
/*
* Start a Timer that elapses after 'periodMSec' milli-seconds
* Support is provided for a one-shot timer. The 'repeatFlag' is
* ignored.
*/
#define A_TIMEOUT_MS(pTimer, periodMSec, repeatFlag) do { \
if (repeatFlag) { \
printk("\n" __FILE__ ":%d: Timer Repeat requested\n",__LINE__); \
panic("Timer Repeat"); \
} \
mod_timer((pTimer), jiffies + HZ * (periodMSec) / 1000); \
} while (0)
/*
* Cancel the Timer.
*/
#define A_UNTIMEOUT(pTimer) do { \
del_timer((pTimer)); \
} while (0)
#define A_DELETE_TIMER(pTimer) do { \
} while (0)
/*
* Wait Queue related functions
*/
typedef wait_queue_head_t A_WAITQUEUE_HEAD;
#define A_INIT_WAITQUEUE_HEAD(head) init_waitqueue_head(head)
#ifndef wait_event_interruptible_timeout
#define __wait_event_interruptible_timeout(wq, condition, ret) \
do { \
wait_queue_t __wait; \
init_waitqueue_entry(&__wait, current); \
\
add_wait_queue(&wq, &__wait); \
for (;;) { \
set_current_state(TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
ret = schedule_timeout(ret); \
if (!ret) \
break; \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
current->state = TASK_RUNNING; \
remove_wait_queue(&wq, &__wait); \
} while (0)
#define wait_event_interruptible_timeout(wq, condition, timeout) \
({ \
long __ret = timeout; \
if (!(condition)) \
__wait_event_interruptible_timeout(wq, condition, __ret); \
__ret; \
})
#endif /* wait_event_interruptible_timeout */
#define A_WAIT_EVENT_INTERRUPTIBLE_TIMEOUT(head, condition, timeout) do { \
wait_event_interruptible_timeout(head, condition, timeout); \
} while (0)
#define A_WAKE_UP(head) wake_up(head)
#ifdef DEBUG
#define A_ASSERT(expr) \
if (!(expr)) { \
printk(KERN_ALERT "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
panic(#expr); \
}
#else
#define A_ASSERT(expr)
#endif /* DEBUG */
/*
* Initialization of the network buffer subsystem
*/
#define A_NETBUF_INIT()
/*
* Network buffer queue support
*/
typedef struct sk_buff_head A_NETBUF_QUEUE_T;
#define A_NETBUF_QUEUE_INIT(q) \
a_netbuf_queue_init(q)
#define A_NETBUF_ENQUEUE(q, pkt) \
a_netbuf_enqueue((q), (pkt))
#define A_NETBUF_PREQUEUE(q, pkt) \
a_netbuf_prequeue((q), (pkt))
#define A_NETBUF_DEQUEUE(q) \
(a_netbuf_dequeue(q))
#define A_NETBUF_QUEUE_SIZE(q) \
a_netbuf_queue_size(q)
#define A_NETBUF_QUEUE_EMPTY(q) \
a_netbuf_queue_empty(q)
/*
* Network buffer support
*/
#define A_NETBUF_ALLOC(size) \
a_netbuf_alloc(size)
#define A_NETBUF_ALLOC_RAW(size) \
a_netbuf_alloc_raw(size)
#define A_NETBUF_FREE(bufPtr) \
a_netbuf_free(bufPtr)
#define A_NETBUF_DATA(bufPtr) \
a_netbuf_to_data(bufPtr)
#define A_NETBUF_LEN(bufPtr) \
a_netbuf_to_len(bufPtr)
#define A_NETBUF_PUSH(bufPtr, len) \
a_netbuf_push(bufPtr, len)
#define A_NETBUF_PUT(bufPtr, len) \
a_netbuf_put(bufPtr, len)
#define A_NETBUF_TRIM(bufPtr,len) \
a_netbuf_trim(bufPtr, len)
#define A_NETBUF_PULL(bufPtr, len) \
a_netbuf_pull(bufPtr, len)
#define A_NETBUF_HEADROOM(bufPtr)\
a_netbuf_headroom(bufPtr)
#define A_NETBUF_SETLEN(bufPtr,len) \
a_netbuf_setlen(bufPtr, len)
/* Add data to end of a buffer */
#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \
a_netbuf_put_data(bufPtr, srcPtr, len)
/* Add data to start of the buffer */
#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \
a_netbuf_push_data(bufPtr, srcPtr, len)
/* Remove data at start of the buffer */
#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \
a_netbuf_pull_data(bufPtr, dstPtr, len)
/* Remove data from the end of the buffer */
#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \
a_netbuf_trim_data(bufPtr, dstPtr, len)
/* View data as "size" contiguous bytes of type "t" */
#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \
(t )( ((struct skbuf *)(bufPtr))->data)
/* return the beginning of the headroom for the buffer */
#define A_NETBUF_HEAD(bufPtr) \
((((struct sk_buff *)(bufPtr))->head))
/*
* OS specific network buffer access routines
*/
void *a_netbuf_alloc(int size);
void *a_netbuf_alloc_raw(int size);
void a_netbuf_free(void *bufPtr);
void *a_netbuf_to_data(void *bufPtr);
A_UINT32 a_netbuf_to_len(void *bufPtr);
A_STATUS a_netbuf_push(void *bufPtr, A_INT32 len);
A_STATUS a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len);
A_STATUS a_netbuf_put(void *bufPtr, A_INT32 len);
A_STATUS a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len);
A_STATUS a_netbuf_pull(void *bufPtr, A_INT32 len);
A_STATUS a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len);
A_STATUS a_netbuf_trim(void *bufPtr, A_INT32 len);
A_STATUS a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len);
A_STATUS a_netbuf_setlen(void *bufPtr, A_INT32 len);
A_INT32 a_netbuf_headroom(void *bufPtr);
void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt);
void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt);
void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q);
int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q);
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q);
/*
* Kernel v.s User space functions
*/
A_UINT32 a_copy_to_user(void *to, const void *from, A_UINT32 n);
A_UINT32 a_copy_from_user(void *to, const void *from, A_UINT32 n);
#else /* __KERNEL__ */
#ifdef __GNUC__
#define __ATTRIB_PACK __attribute__ ((packed))
#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
#define __ATTRIB_NORETURN __attribute__ ((noreturn))
#ifndef INLINE
#define INLINE __inline__
#endif
#else /* Not GCC */
#define __ATTRIB_PACK
#define __ATTRIB_PRINTF
#define __ATTRIB_NORETURN
#ifndef INLINE
#define INLINE __inline
#endif
#endif /* End __GNUC__ */
#define PREPACK
#define POSTPACK __ATTRIB_PACK
#endif /* __KERNEL__ */
#endif /* _OSAPI_LINUX_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,657 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "hif.h"
#include "bmi.h"
#include "htc_api.h"
#include "bmi_internal.h"
/*
Although we had envisioned BMI to run on top of HTC, this is not what the
final implementation boiled down to on dragon. Its a part of BSP and does
not use the HTC protocol either. On the host side, however, we were still
living with the original idea. I think the time has come to accept the truth
and separate it from HTC which has been carrying BMI's burden all this while.
It shall make HTC state machine relatively simpler
*/
/* APIs visible to the driver */
void
BMIInit(void)
{
bmiDone = FALSE;
}
A_STATUS
BMIDone(HIF_DEVICE *device)
{
A_STATUS status;
A_UINT32 cid;
if (bmiDone) {
AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n"));
return A_OK;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device));
bmiDone = TRUE;
cid = BMI_DONE;
status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n"));
return A_OK;
}
A_STATUS
BMIGetTargetInfo(HIF_DEVICE *device, struct bmi_target_info *targ_info)
{
A_STATUS status;
A_UINT32 cid;
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device));
cid = BMI_GET_TARGET_INFO;
status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_ver,
sizeof(targ_info->target_ver));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n"));
return A_ERROR;
}
if (targ_info->target_ver == TARGET_VERSION_SENTINAL) {
/* Determine how many bytes are in the Target's targ_info */
status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_info_byte_count,
sizeof(targ_info->target_info_byte_count));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n"));
return A_ERROR;
}
/*
* The Target's targ_info doesn't match the Host's targ_info.
* We need to do some backwards compatibility work to make this OK.
*/
A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info));
/* Read the remainder of the targ_info */
status = bmiBufferReceive(device,
((A_UCHAR *)targ_info)+sizeof(targ_info->target_info_byte_count),
sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n",
targ_info->target_info_byte_count));
return A_ERROR;
}
} else {
/*
* Target must be an AR6001 whose firmware does not
* support BMI_GET_TARGET_INFO. Construct the data
* that it would have sent.
*/
targ_info->target_info_byte_count = sizeof(targ_info);
targ_info->target_type = TARGET_TYPE_AR6001;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
targ_info->target_ver, targ_info->target_type));
printk("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
targ_info->target_ver, targ_info->target_type);
return A_OK;
}
A_STATUS
BMIReadMemory(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
A_UINT32 remaining, rxlen;
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)];
memset (&data, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
device, address, length));
cid = BMI_READ_MEMORY;
remaining = length;
while (remaining)
{
rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
A_MEMCPY(&data[offset], &rxlen, sizeof(rxlen));
offset += sizeof(length);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
status = bmiBufferReceive(device, data, rxlen);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
return A_ERROR;
}
A_MEMCPY(&buffer[length - remaining], data, rxlen);
remaining -= rxlen; address += rxlen;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n"));
return A_OK;
}
A_STATUS
BMIWriteMemory(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
A_UINT32 remaining, txlen;
const A_UINT32 header = sizeof(cid) + sizeof(address) + sizeof(length);
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)];
memset (&data, 0, header);
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
device, address, length));
cid = BMI_WRITE_MEMORY;
remaining = length;
while (remaining)
{
txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
remaining : (BMI_DATASZ_MAX - header);
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
A_MEMCPY(&data[offset], &txlen, sizeof(txlen));
offset += sizeof(txlen);
A_MEMCPY(&data[offset], &buffer[length - remaining], txlen);
offset += txlen;
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
remaining -= txlen; address += txlen;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n"));
return A_OK;
}
A_STATUS
BMIExecute(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 *param)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(address) + sizeof(*param)];
memset (&data, 0, sizeof(cid) + sizeof(address) + sizeof(*param));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
device, address, *param));
cid = BMI_EXECUTE;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
A_MEMCPY(&data[offset], param, sizeof(*param));
offset += sizeof(*param);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
status = bmiBufferReceive(device, data, sizeof(*param));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
return A_ERROR;
}
A_MEMCPY(param, data, sizeof(*param));
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param));
return A_OK;
}
A_STATUS
BMISetAppStart(HIF_DEVICE *device,
A_UINT32 address)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(address)];
memset (&data, 0, sizeof(cid) + sizeof(address));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n",
device, address));
cid = BMI_SET_APP_START;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n"));
return A_OK;
}
A_STATUS
BMIReadSOCRegister(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 *param)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(address)];
memset (&data, 0, sizeof(cid) + sizeof(address));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n",
device, address));
cid = BMI_READ_SOC_REGISTER;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
status = bmiBufferReceive(device, data, sizeof(*param));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
return A_ERROR;
}
A_MEMCPY(param, data, sizeof(*param));
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param));
return A_OK;
}
A_STATUS
BMIWriteSOCRegister(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 param)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(address) + sizeof(param)];
memset (&data, 0, sizeof(cid) + sizeof(address) + sizeof(param));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
device, address, param));
cid = BMI_WRITE_SOC_REGISTER;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &address, sizeof(address));
offset += sizeof(address);
A_MEMCPY(&data[offset], &param, sizeof(param));
offset += sizeof(param);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n"));
return A_OK;
}
A_STATUS
BMIrompatchInstall(HIF_DEVICE *device,
A_UINT32 ROM_addr,
A_UINT32 RAM_addr,
A_UINT32 nbytes,
A_UINT32 do_activate,
A_UINT32 *rompatch_id)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
sizeof(nbytes) + sizeof(do_activate)];
memset (&data, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
sizeof(nbytes) + sizeof(do_activate));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n",
device, ROM_addr, RAM_addr, nbytes, do_activate));
cid = BMI_ROMPATCH_INSTALL;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &ROM_addr, sizeof(ROM_addr));
offset += sizeof(ROM_addr);
A_MEMCPY(&data[offset], &RAM_addr, sizeof(RAM_addr));
offset += sizeof(RAM_addr);
A_MEMCPY(&data[offset], &nbytes, sizeof(nbytes));
offset += sizeof(nbytes);
A_MEMCPY(&data[offset], &do_activate, sizeof(do_activate));
offset += sizeof(do_activate);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
status = bmiBufferReceive(device, (A_UCHAR *)rompatch_id, sizeof(*rompatch_id));
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id));
return A_OK;
}
A_STATUS
BMIrompatchUninstall(HIF_DEVICE *device,
A_UINT32 rompatch_id)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[sizeof(cid) + sizeof(rompatch_id)];
memset (&data, 0, sizeof(cid) + sizeof(rompatch_id));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n",
device, rompatch_id));
cid = BMI_ROMPATCH_UNINSTALL;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &rompatch_id, sizeof(rompatch_id));
offset += sizeof(rompatch_id);
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id));
return A_OK;
}
static A_STATUS
_BMIrompatchChangeActivation(HIF_DEVICE *device,
A_UINT32 rompatch_count,
A_UINT32 *rompatch_list,
A_UINT32 do_activate)
{
A_UINT32 cid;
A_STATUS status;
A_UINT32 offset;
static A_UCHAR data[BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)];
A_UINT32 length;
memset (&data, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count));
if (bmiDone) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n",
device, rompatch_count));
cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE;
offset = 0;
A_MEMCPY(&data[offset], &cid, sizeof(cid));
offset += sizeof(cid);
A_MEMCPY(&data[offset], &rompatch_count, sizeof(rompatch_count));
offset += sizeof(rompatch_count);
length = rompatch_count * sizeof(*rompatch_list);
A_MEMCPY(&data[offset], rompatch_list, length);
offset += length;
status = bmiBufferSend(device, data, offset);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
return A_ERROR;
}
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n"));
return A_OK;
}
A_STATUS
BMIrompatchActivate(HIF_DEVICE *device,
A_UINT32 rompatch_count,
A_UINT32 *rompatch_list)
{
return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1);
}
A_STATUS
BMIrompatchDeactivate(HIF_DEVICE *device,
A_UINT32 rompatch_count,
A_UINT32 *rompatch_list)
{
return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0);
}
/* BMI Access routines */
A_STATUS
bmiBufferSend(HIF_DEVICE *device,
A_UCHAR *buffer,
A_UINT32 length)
{
A_STATUS status;
A_UINT32 timeout;
A_UINT32 address;
static A_UINT32 cmdCredits;
A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
&mboxAddress, sizeof(mboxAddress));
cmdCredits = 0;
timeout = BMI_COMMUNICATION_TIMEOUT;
while(timeout-- && !cmdCredits) {
/* Read the counter register to get the command credits */
address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
/* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause
* a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to
* make all HIF accesses 4-byte aligned */
status = HIFReadWrite(device, address, (A_UINT8 *)&cmdCredits, 4,
HIF_RD_SYNC_BYTE_INC, NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n"));
return A_ERROR;
}
/* the counter is only 8=bits, ignore anything in the upper 3 bytes */
cmdCredits &= 0xFF;
}
if (cmdCredits) {
address = mboxAddress[ENDPOINT1];
status = HIFReadWrite(device, address, buffer, length,
HIF_WR_SYNC_BYTE_INC, NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n"));
return A_ERROR;
}
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout\n"));
return A_ERROR;
}
return status;
}
A_STATUS
bmiBufferReceive(HIF_DEVICE *device,
A_UCHAR *buffer,
A_UINT32 length)
{
A_STATUS status;
A_UINT32 address;
A_UINT32 timeout;
static A_UINT32 cmdCredits;
A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
&mboxAddress, sizeof(mboxAddress));
cmdCredits = 0;
timeout = BMI_COMMUNICATION_TIMEOUT;
while(timeout-- && !cmdCredits) {
/* Read the counter register to get the command credits */
address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1;
/* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing,
* we can read this counter multiple times using a non-incrementing address mode.
* The rationale here is to make all HIF accesses a multiple of 4 bytes */
status = HIFReadWrite(device, address, (A_UINT8 *)&cmdCredits, sizeof(cmdCredits),
HIF_RD_SYNC_BYTE_FIX, NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n"));
return A_ERROR;
}
/* we did a 4-byte read to the same count register so mask off upper bytes */
cmdCredits &= 0xFF;
status = A_ERROR;
}
if (cmdCredits) {
address = mboxAddress[ENDPOINT1];
status = HIFReadWrite(device, address, buffer, length,
HIF_RD_SYNC_BYTE_INC, NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n"));
return A_ERROR;
}
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Communication timeout\n"));
return A_ERROR;
}
return status;
}

View file

@ -0,0 +1,45 @@
#ifndef BMI_INTERNAL_H
#define BMI_INTERNAL_H
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "AR6Khwreg.h"
#include "bmi_msg.h"
#define BMI_COMMUNICATION_TIMEOUT 100000
/* ------ Global Variable Declarations ------- */
A_BOOL bmiDone;
A_STATUS
bmiBufferSend(HIF_DEVICE *device,
A_UCHAR *buffer,
A_UINT32 length);
A_STATUS
bmiBufferReceive(HIF_DEVICE *device,
A_UCHAR *buffer,
A_UINT32 length);
#endif

View file

@ -0,0 +1,824 @@
/*
* @file: hif.c
*
* @abstract: HIF layer reference implementation for Atheros SDIO stack
*
* @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "hif_internal.h"
/* ------ Static Variables ------ */
/* ------ Global Variable Declarations ------- */
SD_PNP_INFO Ids[] = {
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xB,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xA,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x9,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x8,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x0,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
.SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x1,
.SDIO_ManufacturerCode = MANUFACTURER_CODE,
.SDIO_FunctionClass = FUNCTION_CLASS,
.SDIO_FunctionNo = 1
},
{
} //list is null termintaed
};
TARGET_FUNCTION_CONTEXT FunctionContext = {
.function.Version = CT_SDIO_STACK_VERSION_CODE,
.function.pName = "sdio_wlan",
.function.MaxDevices = 1,
.function.NumDevices = 0,
.function.pIds = Ids,
.function.pProbe = hifDeviceInserted,
.function.pRemove = hifDeviceRemoved,
.function.pSuspend = NULL,
.function.pResume = NULL,
.function.pWake = NULL,
.function.pContext = &FunctionContext,
};
HIF_DEVICE hifDevice[HIF_MAX_DEVICES];
HTC_CALLBACKS htcCallbacks;
BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM];
static BUS_REQUEST *s_busRequestFreeQueue = NULL;
OS_CRITICALSECTION lock;
extern A_UINT32 onebitmode;
extern A_UINT32 busspeedlow;
#ifdef DEBUG
extern A_UINT32 debughif;
#define ATH_DEBUG_ERROR 1
#define ATH_DEBUG_WARN 2
#define ATH_DEBUG_TRACE 3
#define _AR_DEBUG_PRINTX_ARG(arg...) arg
#define AR_DEBUG_PRINTF(lvl, args)\
{if (lvl <= debughif)\
A_PRINTF(KERN_ALERT _AR_DEBUG_PRINTX_ARG args);\
}
#else
#define AR_DEBUG_PRINTF(lvl, args)
#endif
static BUS_REQUEST *hifAllocateBusRequest(void);
static void hifFreeBusRequest(BUS_REQUEST *busrequest);
static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper);
static void ResetAllCards(void);
/* ------ Functions ------ */
int HIFInit(HTC_CALLBACKS *callbacks)
{
SDIO_STATUS status;
DBG_ASSERT(callbacks != NULL);
/* Store the callback and event handlers */
htcCallbacks.deviceInsertedHandler = callbacks->deviceInsertedHandler;
htcCallbacks.deviceRemovedHandler = callbacks->deviceRemovedHandler;
htcCallbacks.deviceSuspendHandler = callbacks->deviceSuspendHandler;
htcCallbacks.deviceResumeHandler = callbacks->deviceResumeHandler;
htcCallbacks.deviceWakeupHandler = callbacks->deviceWakeupHandler;
htcCallbacks.rwCompletionHandler = callbacks->rwCompletionHandler;
htcCallbacks.dsrHandler = callbacks->dsrHandler;
CriticalSectionInit(&lock);
/* Register with bus driver core */
status = SDIO_RegisterFunction(&FunctionContext.function);
DBG_ASSERT(SDIO_SUCCESS(status));
return(0);
}
A_STATUS
HIFReadWrite(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length,
A_UINT32 request,
void *context)
{
A_UINT8 rw;
A_UINT8 mode;
A_UINT8 funcNo;
A_UINT8 opcode;
A_UINT16 count;
SDREQUEST *sdrequest;
SDIO_STATUS sdiostatus;
BUS_REQUEST *busrequest;
A_STATUS status = A_OK;
DBG_ASSERT(device != NULL);
DBG_ASSERT(device->handle != NULL);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
do {
busrequest = hifAllocateBusRequest();
if (busrequest == NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF Unable to allocate bus request\n"));
status = A_NO_RESOURCE;
break;
}
sdrequest = busrequest->request;
busrequest->context = context;
sdrequest->pDataBuffer = buffer;
if (request & HIF_SYNCHRONOUS) {
sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS;
sdrequest->pCompleteContext = NULL;
sdrequest->pCompletion = NULL;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Synchronous\n"));
} else if (request & HIF_ASYNCHRONOUS) {
sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS |
SDREQ_FLAGS_TRANS_ASYNC;
sdrequest->pCompleteContext = busrequest;
sdrequest->pCompletion = hifRWCompletionHandler;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Asynchronous\n"));
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Invalid execution mode: 0x%08x\n", request));
status = A_EINVAL;
break;
}
if (request & HIF_EXTENDED_IO) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Command type: CMD53\n"));
sdrequest->Command = CMD53;
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Invalid command type: 0x%08x\n", request));
status = A_EINVAL;
break;
}
if (request & HIF_BLOCK_BASIS) {
mode = CMD53_BLOCK_BASIS;
sdrequest->BlockLen = HIF_MBOX_BLOCK_SIZE;
sdrequest->BlockCount = length / HIF_MBOX_BLOCK_SIZE;
count = sdrequest->BlockCount;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Block mode (BlockLen: %d, BlockCount: %d)\n",
sdrequest->BlockLen, sdrequest->BlockCount));
} else if (request & HIF_BYTE_BASIS) {
mode = CMD53_BYTE_BASIS;
sdrequest->BlockLen = length;
sdrequest->BlockCount = 1;
count = sdrequest->BlockLen;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Byte mode (BlockLen: %d, BlockCount: %d)\n",
sdrequest->BlockLen, sdrequest->BlockCount));
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Invalid data mode: 0x%08x\n", request));
status = A_EINVAL;
break;
}
#if 0
/* useful for checking register accesses */
if (length & 0x3) {
A_PRINTF(KERN_ALERT"HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
request & HIF_WRITE ? "write":"read", address, length);
}
#endif
if ((address >= HIF_MBOX_START_ADDR(0)) &&
(address <= HIF_MBOX_END_ADDR(3)))
{
DBG_ASSERT(length <= HIF_MBOX_WIDTH);
/*
* Mailbox write. Adjust the address so that the last byte
* falls on the EOM address.
*/
address += (HIF_MBOX_WIDTH - length);
}
if (request & HIF_WRITE) {
rw = CMD53_WRITE;
sdrequest->Flags |= SDREQ_FLAGS_DATA_WRITE;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Write\n"));
} else if (request & HIF_READ) {
rw = CMD53_READ;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Read\n"));
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Invalid direction: 0x%08x\n", request));
status = A_EINVAL;
break;
}
if (request & HIF_FIXED_ADDRESS) {
opcode = CMD53_FIXED_ADDRESS;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Fixed\n"));
} else if (request & HIF_INCREMENTAL_ADDRESS) {
opcode = CMD53_INCR_ADDRESS;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Incremental\n"));
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Invalid address mode: 0x%08x\n", request));
status = A_EINVAL;
break;
}
funcNo = SDDEVICE_GET_SDIO_FUNCNO(device->handle);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Function number: %d\n", funcNo));
SDIO_SET_CMD53_ARG(sdrequest->Argument, rw, funcNo,
mode, opcode, address, count);
/* Send the command out */
sdiostatus = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest);
if (!SDIO_SUCCESS(sdiostatus)) {
status = A_ERROR;
}
} while (FALSE);
if (A_FAILED(status) || (request & HIF_SYNCHRONOUS)) {
if (busrequest != NULL) {
hifFreeBusRequest(busrequest);
}
}
if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) {
/* call back async handler on failure */
htcCallbacks.rwCompletionHandler(context, status);
}
return status;
}
A_STATUS
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
void *config, A_UINT32 configLen)
{
A_UINT32 count;
switch(opcode) {
case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
((A_UINT32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
((A_UINT32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
((A_UINT32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
((A_UINT32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
break;
case HIF_DEVICE_GET_MBOX_ADDR:
for (count = 0; count < 4; count ++) {
((A_UINT32 *)config)[count] = HIF_MBOX_START_ADDR(count);
}
break;
case HIF_DEVICE_GET_IRQ_PROC_MODE:
/* the SDIO stack allows the interrupts to be processed either way, ASYNC or SYNC */
*((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_ASYNC_SYNC;
break;
default:
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
("Unsupported configuration opcode: %d\n", opcode));
return A_ERROR;
}
return A_OK;
}
void
HIFShutDownDevice(HIF_DEVICE *device)
{
A_UINT8 data;
A_UINT32 count;
SDIO_STATUS status;
SDCONFIG_BUS_MODE_DATA busSettings;
SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
if (device != NULL) {
DBG_ASSERT(device->handle != NULL);
/* Remove the allocated current if any */
status = SDLIB_IssueConfig(device->handle,
SDCONFIG_FUNC_FREE_SLOT_CURRENT, NULL, 0);
DBG_ASSERT(SDIO_SUCCESS(status));
/* Disable the card */
fData.EnableFlags = SDCONFIG_DISABLE_FUNC;
fData.TimeOut = 1;
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ENABLE_DISABLE,
&fData, sizeof(fData));
DBG_ASSERT(SDIO_SUCCESS(status));
/* Perform a soft I/O reset */
data = SDIO_IO_RESET;
status = SDLIB_IssueCMD52(device->handle, 0, SDIO_IO_ABORT_REG,
&data, 1, 1);
DBG_ASSERT(SDIO_SUCCESS(status));
/*
* WAR - Codetelligence driver does not seem to shutdown correctly in 1
* bit mode. By default it configures the HC in the 4 bit. Its later in
* our driver that we switch to 1 bit mode. If we try to shutdown, the
* driver hangs so we revert to 4 bit mode, to be transparent to the
* underlying bus driver.
*/
if (onebitmode) {
ZERO_OBJECT(busSettings);
busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(device->handle);
SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
SDCONFIG_BUS_WIDTH_4_BIT);
/* Issue config request to change the bus width to 4 bit */
status = SDLIB_IssueConfig(device->handle, SDCONFIG_BUS_MODE_CTRL,
&busSettings,
sizeof(SDCONFIG_BUS_MODE_DATA));
DBG_ASSERT(SDIO_SUCCESS(status));
}
/* Free the bus requests */
for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
SDDeviceFreeRequest(device->handle, busRequest[count].request);
}
/* Clean up the queue */
s_busRequestFreeQueue = NULL;
} else {
/* since we are unloading the driver anyways, reset all cards in case the SDIO card
* is externally powered and we are unloading the SDIO stack. This avoids the problem when
* the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
* enumerated */
ResetAllCards();
/* Unregister with bus driver core */
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Unregistering with the bus driver\n"));
status = SDIO_UnregisterFunction(&FunctionContext.function);
DBG_ASSERT(SDIO_SUCCESS(status));
}
}
void
hifRWCompletionHandler(SDREQUEST *request)
{
A_STATUS status;
void *context;
BUS_REQUEST *busrequest;
if (SDIO_SUCCESS(request->Status)) {
status = A_OK;
} else {
status = A_ERROR;
}
DBG_ASSERT(status == A_OK);
busrequest = (BUS_REQUEST *) request->pCompleteContext;
context = (void *) busrequest->context;
/* free the request before calling the callback, in case the
* callback submits another request, this guarantees that
* there is at least 1 free request available everytime the callback
* is invoked */
hifFreeBusRequest(busrequest);
htcCallbacks.rwCompletionHandler(context, status);
}
void
hifIRQHandler(void *context)
{
A_STATUS status;
HIF_DEVICE *device;
device = (HIF_DEVICE *)context;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
status = htcCallbacks.dsrHandler(device->htc_handle);
DBG_ASSERT(status == A_OK);
}
BOOL
hifDeviceInserted(SDFUNCTION *function, SDDEVICE *handle)
{
BOOL enabled;
A_UINT8 data;
A_UINT32 count;
HIF_DEVICE *device;
SDIO_STATUS status;
A_UINT16 maxBlocks;
A_UINT16 maxBlockSize;
SDCONFIG_BUS_MODE_DATA busSettings;
SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
TARGET_FUNCTION_CONTEXT *functionContext;
SDCONFIG_FUNC_SLOT_CURRENT_DATA slotCurrent;
SD_BUSCLOCK_RATE currentBusClock;
DBG_ASSERT(function != NULL);
DBG_ASSERT(handle != NULL);
device = addHifDevice(handle);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
functionContext = (TARGET_FUNCTION_CONTEXT *)function->pContext;
/*
* Issue commands to get the manufacturer ID and stuff and compare it
* against the rev Id derived from the ID registered during the
* initialization process. Report the device only in the case there
* is a match. In the case od SDIO, the bus driver has already queried
* these details so we just need to use their data structures to get the
* relevant values. Infact, the driver has already matched it against
* the Ids that we registered with it so we dont need to the step here.
*/
/* Configure the SDIO Bus Width */
if (onebitmode) {
data = SDIO_BUS_WIDTH_1_BIT;
status = SDLIB_IssueCMD52(handle, 0, SDIO_BUS_IF_REG, &data, 1, 1);
if (!SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Unable to set the bus width to 1 bit\n"));
return FALSE;
}
}
/* Get current bus flags */
ZERO_OBJECT(busSettings);
busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(handle);
if (onebitmode) {
SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
SDCONFIG_BUS_WIDTH_1_BIT);
}
/* get the current operating clock, the bus driver sets us up based
* on what our CIS reports and what the host controller can handle
* we can use this to determine whether we want to drop our clock rate
* down */
currentBusClock = SDDEVICE_GET_OPER_CLOCK(handle);
busSettings.ClockRate = currentBusClock;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("HIF currently running at: %d \n",currentBusClock));
/* see if HIF wants to run at a lower clock speed, we may already be
* at that lower clock speed */
if (currentBusClock > (SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow)) {
busSettings.ClockRate = SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow;
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
("HIF overriding clock to %d \n",busSettings.ClockRate));
}
/* Issue config request to override clock rate */
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_CHANGE_BUS_MODE, &busSettings,
sizeof(SDCONFIG_BUS_MODE_DATA));
if (!SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Unable to configure the host clock\n"));
return FALSE;
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Configured clock: %d, Maximum clock: %d\n",
busSettings.ActualClockRate,
SDDEVICE_GET_MAX_CLOCK(handle)));
}
/*
* Check if the target supports block mode. This result of this check
* can be used to implement the HIFReadWrite API.
*/
if (SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle)) {
/* Limit block size to operational block limit or card function
capability */
maxBlockSize = min(SDDEVICE_GET_OPER_BLOCK_LEN(handle),
SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle));
/* check if the card support multi-block transfers */
if (!(SDDEVICE_GET_SDIOCARD_CAPS(handle) & SDIO_CAPS_MULTI_BLOCK)) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Byte basis only\n"));
/* Limit block size to max byte basis */
maxBlockSize = min(maxBlockSize,
(A_UINT16)SDIO_MAX_LENGTH_BYTE_BASIS);
maxBlocks = 1;
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Multi-block capable\n"));
maxBlocks = SDDEVICE_GET_OPER_BLOCKS(handle);
status = SDLIB_SetFunctionBlockSize(handle, HIF_MBOX_BLOCK_SIZE);
if (!SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Failed to set block size. Err:%d\n", status));
return FALSE;
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Bytes Per Block: %d bytes, Block Count:%d \n",
maxBlockSize, maxBlocks));
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Function does not support Block Mode!\n"));
return FALSE;
}
/* Allocate the slot current */
status = SDLIB_GetDefaultOpCurrent(handle, &slotCurrent.SlotCurrent);
if (SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Allocating Slot current: %d mA\n",
slotCurrent.SlotCurrent));
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ALLOC_SLOT_CURRENT,
&slotCurrent, sizeof(slotCurrent));
if (!SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Failed to allocate slot current %d\n", status));
return FALSE;
}
}
/* Enable the dragon function */
count = 0;
enabled = FALSE;
fData.TimeOut = 1;
fData.EnableFlags = SDCONFIG_ENABLE_FUNC;
while ((count++ < SDWLAN_ENABLE_DISABLE_TIMEOUT) && !enabled)
{
/* Enable dragon */
status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ENABLE_DISABLE,
&fData, sizeof(fData));
if (!SDIO_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Attempting to enable the card again\n"));
continue;
}
/* Mark the status as enabled */
enabled = TRUE;
}
/* Check if we were succesful in enabling the target */
if (!enabled) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
("Failed to communicate with the target\n"));
return FALSE;
}
/* Allocate the bus requests to be used later */
A_MEMZERO(busRequest, sizeof(busRequest));
for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
if ((busRequest[count].request = SDDeviceAllocRequest(handle)) == NULL){
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate memory\n"));
/* TODO: Free the memory that has already been allocated */
return FALSE;
}
hifFreeBusRequest(&busRequest[count]);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("0x%08x = busRequest[%d].request = 0x%08x\n",
(unsigned int) &busRequest[count], count,
(unsigned int) busRequest[count].request));
}
/* Schedule a worker to handle device inserted, this is a temporary workaround
* to fix a deadlock if the device fails to intialize in the insertion handler
* The failure causes the instance to shutdown the HIF layer and unregister the
* function driver within the busdriver probe context which can deadlock
*
* NOTE: we cannot use the default work queue because that would block
* SD bus request processing for all synchronous I/O. We must use a kernel
* thread that is creating using the helper library.
* */
if (SDIO_SUCCESS(SDLIB_OSCreateHelper(&device->insert_helper,
insert_helper_func,
device))) {
device->helper_started = TRUE;
}
return TRUE;
}
static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper)
{
/*
* Adding a wait of around a second before we issue the very first
* command to dragon. During the process of loading/unloading the
* driver repeatedly it was observed that we get a data timeout
* while accessing function 1 registers in the chip. The theory at
* this point is that some initialization delay in dragon is
* causing the SDIO state in dragon core to be not ready even after
* the ready bit indicates that function 1 is ready. Accomodating
* for this behavior by adding some delay in the driver before it
* issues the first command after switching on dragon. Need to
* investigate this a bit more - TODO
*/
A_MDELAY(1000);
/* Inform HTC */
if ((htcCallbacks.deviceInsertedHandler(SD_GET_OS_HELPER_CONTEXT(pHelper))) != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device rejected\n"));
}
return 0;
}
void
HIFAckInterrupt(HIF_DEVICE *device)
{
SDIO_STATUS status;
DBG_ASSERT(device != NULL);
DBG_ASSERT(device->handle != NULL);
/* Acknowledge our function IRQ */
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ACK_IRQ,
NULL, 0);
DBG_ASSERT(SDIO_SUCCESS(status));
}
void
HIFUnMaskInterrupt(HIF_DEVICE *device)
{
SDIO_STATUS status;
DBG_ASSERT(device != NULL);
DBG_ASSERT(device->handle != NULL);
/* Register the IRQ Handler */
SDDEVICE_SET_IRQ_HANDLER(device->handle, hifIRQHandler, device);
/* Unmask our function IRQ */
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ,
NULL, 0);
DBG_ASSERT(SDIO_SUCCESS(status));
}
void HIFMaskInterrupt(HIF_DEVICE *device)
{
SDIO_STATUS status;
DBG_ASSERT(device != NULL);
DBG_ASSERT(device->handle != NULL);
/* Mask our function IRQ */
status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_MASK_IRQ,
NULL, 0);
DBG_ASSERT(SDIO_SUCCESS(status));
/* Unregister the IRQ Handler */
SDDEVICE_SET_IRQ_HANDLER(device->handle, NULL, NULL);
}
static BUS_REQUEST *hifAllocateBusRequest(void)
{
BUS_REQUEST *busrequest;
/* Acquire lock */
CriticalSectionAcquire(&lock);
/* Remove first in list */
if((busrequest = s_busRequestFreeQueue) != NULL)
{
s_busRequestFreeQueue = busrequest->next;
}
/* Release lock */
CriticalSectionRelease(&lock);
return busrequest;
}
static void
hifFreeBusRequest(BUS_REQUEST *busrequest)
{
DBG_ASSERT(busrequest != NULL);
/* Acquire lock */
CriticalSectionAcquire(&lock);
/* Insert first in list */
busrequest->next = s_busRequestFreeQueue;
s_busRequestFreeQueue = busrequest;
/* Release lock */
CriticalSectionRelease(&lock);
}
void
hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *handle)
{
A_STATUS status;
HIF_DEVICE *device;
DBG_ASSERT(function != NULL);
DBG_ASSERT(handle != NULL);
device = getHifDevice(handle);
status = htcCallbacks.deviceRemovedHandler(device->htc_handle, A_OK);
/* cleanup the helper thread */
if (device->helper_started) {
SDLIB_OSDeleteHelper(&device->insert_helper);
device->helper_started = FALSE;
}
delHifDevice(handle);
DBG_ASSERT(status == A_OK);
}
HIF_DEVICE *
addHifDevice(SDDEVICE *handle)
{
DBG_ASSERT(handle != NULL);
hifDevice[0].handle = handle;
return &hifDevice[0];
}
HIF_DEVICE *
getHifDevice(SDDEVICE *handle)
{
DBG_ASSERT(handle != NULL);
return &hifDevice[0];
}
void
delHifDevice(SDDEVICE *handle)
{
DBG_ASSERT(handle != NULL);
hifDevice[0].handle = NULL;
}
struct device*
HIFGetOSDevice(HIF_DEVICE *device)
{
return &device->handle->Device->dev;
}
static void ResetAllCards(void)
{
UINT8 data;
SDIO_STATUS status;
int i;
data = SDIO_IO_RESET;
/* set the I/O CARD reset bit:
* NOTE: we are exploiting a "feature" of the SDIO core that resets the core when you
* set the RES bit in the SDIO_IO_ABORT register. This bit however "normally" resets the
* I/O functions leaving the SDIO core in the same state (as per SDIO spec).
* In this design, this reset can be used to reset the SDIO core itself */
for (i = 0; i < HIF_MAX_DEVICES; i++) {
if (hifDevice[i].handle != NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("Issuing I/O Card reset for instance: %d \n",i));
/* set the I/O Card reset bit */
status = SDLIB_IssueCMD52(hifDevice[i].handle,
0, /* function 0 space */
SDIO_IO_ABORT_REG,
&data,
1, /* 1 byte */
TRUE); /* write */
}
}
}
void HIFSetHandle(void *hif_handle, void *handle)
{
HIF_DEVICE *device = (HIF_DEVICE *) hif_handle;
device->htc_handle = handle;
return;
}

View file

@ -0,0 +1,768 @@
/*
* hif2.c - HIF layer re-implementation for the Linux SDIO stack
*
* Copyright (C) 2008, 2009 by OpenMoko, Inc.
* Written by Werner Almesberger <werner@openmoko.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Based on:
*
* @abstract: HIF layer reference implementation for Atheros SDIO stack
* @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
*/
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include "athdefs.h"
#include "a_types.h"
#include "hif.h"
/* @@@ Hack - this wants cleaning up */
#ifdef CONFIG_MACH_NEO1973_GTA02
#include <mach/gta02-pm-wlan.h>
#else /* CONFIG_MACH_NEO1973_GTA02 */
#define gta02_wlan_query_rfkill_lock() 1
#define gta02_wlan_set_rfkill_cb(cb, hif) ((void) cb)
#define gta02_wlan_query_rfkill_unlock()
#define gta02_wlan_clear_rfkill_cb()
#endif /* !CONFIG_MACH_NEO1973_GTA02 */
/*
* KNOWN BUGS:
*
* - HIF_DEVICE_IRQ_ASYNC_SYNC doesn't work yet (gets MMC errors)
* - latency can reach hundreds of ms, probably because of scheduling delays
* - packets go through about three queues before finally hitting the network
*/
/*
* Differences from Atheros' HIFs:
*
* - synchronous and asynchronous requests may get reordered with respect to
* each other, e.g., if HIFReadWrite returns for an asynchronous request and
* then HIFReadWrite is called for a synchronous request, the synchronous
* request may be executed before the asynchronous request.
*
* - request queue locking seems unnecessarily complex in the Atheros HIFs.
*
* - Atheros mask interrupts by calling sdio_claim_irq/sdio_release_irq, which
* can cause quite a bit of overhead. This HIF has its own light-weight
* interrupt masking.
*
* - Atheros call deviceInsertedHandler from a thread spawned off the probe or
* device insertion function. The original explanation for the Atheros SDIO
* stack said that this is done because a delay is needed to let the chip
* complete initialization. There is indeed a one second delay in the thread.
*
* The Atheros Linux SDIO HIF removes the delay and only retains the thread.
* Experimentally removing the thread didn't show any conflicts, so let's get
* rid of it for good.
*
* - The Atheros SDIO stack with Samuel's driver sets SDIO_CCCR_POWER in
* SDIO_POWER_EMPC. Atheros' Linux SDIO code apparently doesn't. We don't
* either, and this seems to work fine.
* @@@ Need to check this with Atheros.
*/
#define MBOXES 4
#define HIF_MBOX_BLOCK_SIZE 128
#define HIF_MBOX_BASE_ADDR 0x800
#define HIF_MBOX_WIDTH 0x800
#define HIF_MBOX_START_ADDR(mbox) \
(HIF_MBOX_BASE_ADDR+(mbox)*HIF_MBOX_WIDTH)
struct hif_device {
void *htc_handle;
struct sdio_func *func;
/*
* @@@ our sweet little bit of bogosity - the mechanism that lets us
* use the SDIO stack from softirqs. This really wants to use skbs.
*/
struct list_head queue;
spinlock_t queue_lock;
struct task_struct *io_task;
wait_queue_head_t wait;
/*
* activate_lock protects "active" and the activation/deactivation
* process itself.
*
* Relation to other locks: The SDIO function can be claimed while
* activate_lock is being held, but trying to acquire activate_lock
* while having ownership of the SDIO function could cause a deadlock.
*/
int active;
struct mutex activate_lock;
};
struct hif_request {
struct list_head list;
struct sdio_func *func;
int (*read)(struct sdio_func *func,
void *dst, unsigned int addr, int count);
int (*write)(struct sdio_func *func,
unsigned int addr, void *src, int count);
void *buf;
unsigned long addr;
int len;
A_STATUS (*completion)(void *context, A_STATUS status);
void *context;
};
static HTC_CALLBACKS htcCallbacks;
/*
* shutdown_lock prevents recursion through HIFShutDownDevice
*/
static DEFINE_MUTEX(shutdown_lock);
/* ----- Request processing ------------------------------------------------ */
static A_STATUS process_request(struct hif_request *req)
{
int ret;
A_STATUS status;
dev_dbg(&req->func->dev, "process_request(req %p)\n", req);
sdio_claim_host(req->func);
if (req->read) {
ret = req->read(req->func, req->buf, req->addr, req->len);
} else {
ret = req->write(req->func, req->addr, req->buf, req->len);
}
sdio_release_host(req->func);
status = ret ? A_ERROR : A_OK;
if (req->completion)
req->completion(req->context, status);
kfree(req);
return status;
}
static void enqueue_request(struct hif_device *hif, struct hif_request *req)
{
unsigned long flags;
dev_dbg(&req->func->dev, "enqueue_request(req %p)\n", req);
spin_lock_irqsave(&hif->queue_lock, flags);
list_add_tail(&req->list, &hif->queue);
spin_unlock_irqrestore(&hif->queue_lock, flags);
wake_up(&hif->wait);
}
static struct hif_request *dequeue_request(struct hif_device *hif)
{
struct hif_request *req;
unsigned long flags;
spin_lock_irqsave(&hif->queue_lock, flags);
if (list_empty(&hif->queue))
req = NULL;
else {
req = list_first_entry(&hif->queue,
struct hif_request, list);
list_del(&req->list);
}
spin_unlock_irqrestore(&hif->queue_lock, flags);
return req;
}
static void wait_queue_empty(struct hif_device *hif)
{
unsigned long flags;
int empty;
while (1) {
spin_lock_irqsave(&hif->queue_lock, flags);
empty = list_empty(&hif->queue);
spin_unlock_irqrestore(&hif->queue_lock, flags);
if (empty)
break;
else
yield();
}
}
static int io(void *data)
{
struct hif_device *hif = data;
struct sched_param param = { .sched_priority = 2 };
/* one priority level slower than ksdioirqd (which is at 1) */
DEFINE_WAIT(wait);
struct hif_request *req;
sched_setscheduler(current, SCHED_FIFO, &param);
while (1) {
while (1) {
/*
* Since we never use signals here, one might think
* that this ought to be TASK_UNINTERRUPTIBLE. However,
* such a task would increase the load average and,
* worse, it would trigger the softlockup check.
*/
prepare_to_wait(&hif->wait, &wait, TASK_INTERRUPTIBLE);
if (kthread_should_stop()) {
finish_wait(&hif->wait, &wait);
return 0;
}
req = dequeue_request(hif);
if (req)
break;
schedule();
}
finish_wait(&hif->wait, &wait);
(void) process_request(req);
}
return 0;
}
A_STATUS HIFReadWrite(HIF_DEVICE *hif, A_UINT32 address, A_UCHAR *buffer,
A_UINT32 length, A_UINT32 request, void *context)
{
struct device *dev = HIFGetOSDevice(hif);
struct hif_request *req;
dev_dbg(dev, "HIFReadWrite(device %p, address 0x%x, buffer %p, "
"length %d, request 0x%x, context %p)\n",
hif, address, buffer, length, request, context);
BUG_ON(!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)));
BUG_ON(!(request & (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)));
BUG_ON(!(request & (HIF_READ | HIF_WRITE)));
BUG_ON(!(request & HIF_EXTENDED_IO));
if (address >= HIF_MBOX_START_ADDR(0) &&
address < HIF_MBOX_START_ADDR(MBOXES+1)) {
BUG_ON(length > HIF_MBOX_WIDTH);
/* Adjust the address so that the last byte falls on the EOM
address. */
address += HIF_MBOX_WIDTH-length;
}
req = kzalloc(sizeof(*req), GFP_ATOMIC);
if (!req) {
if (request & HIF_ASYNCHRONOUS)
htcCallbacks.rwCompletionHandler(context, A_ERROR);
return A_ERROR;
}
req->func = hif->func;
req->addr = address;
req->buf = buffer;
req->len = length;
if (request & HIF_READ) {
if (request & HIF_FIXED_ADDRESS)
req->read = sdio_readsb;
else
req->read = sdio_memcpy_fromio;
} else {
if (request & HIF_FIXED_ADDRESS)
req->write = sdio_writesb;
else
req->write = sdio_memcpy_toio;
}
if (!(request & HIF_ASYNCHRONOUS))
return process_request(req);
req->completion = htcCallbacks.rwCompletionHandler;
req->context = context;
enqueue_request(hif, req);
return A_OK;
}
/* ----- Interrupt handling ------------------------------------------------ */
/*
* Volatile ought to be good enough to make gcc do the right thing on S3C24xx.
* No need to use atomic or put barriers, keeping the code more readable.
*
* Warning: this story changes if going SMP/SMT.
*/
static volatile int masked = 1;
static volatile int pending;
static volatile int in_interrupt;
static void ar6000_do_irq(struct sdio_func *func)
{
HIF_DEVICE *hif = sdio_get_drvdata(func);
struct device *dev = HIFGetOSDevice(hif);
A_STATUS status;
dev_dbg(dev, "ar6000_do_irq -> %p\n", htcCallbacks.dsrHandler);
status = htcCallbacks.dsrHandler(hif->htc_handle);
BUG_ON(status != A_OK);
}
static void sdio_ar6000_irq(struct sdio_func *func)
{
HIF_DEVICE *hif = sdio_get_drvdata(func);
struct device *dev = HIFGetOSDevice(hif);
dev_dbg(dev, "sdio_ar6000_irq\n");
in_interrupt = 1;
if (masked) {
in_interrupt = 0;
pending++;
return;
}
/*
* @@@ This is ugly. If we don't drop the lock, we'll deadlock when
* the handler tries to do SDIO. So there are four choices:
*
* 1) Break the call chain by calling the callback from a workqueue.
* Ugh.
* 2) Make process_request aware that we already have the lock.
* 3) Drop the lock. Which is ugly but should be safe as long as we're
* making sure the device doesn't go away.
* 4) Change the AR6k driver such that it only issues asynchronous
* quests when called from an interrupt.
*
* Solution 2) is probably the best for now. Will try it later.
*/
sdio_release_host(func);
ar6000_do_irq(func);
sdio_claim_host(func);
in_interrupt = 0;
}
void HIFAckInterrupt(HIF_DEVICE *hif)
{
struct device *dev = HIFGetOSDevice(hif);
dev_dbg(dev, "HIFAckInterrupt\n");
/* do nothing */
}
void HIFUnMaskInterrupt(HIF_DEVICE *hif)
{
struct device *dev = HIFGetOSDevice(hif);
dev_dbg(dev, "HIFUnMaskInterrupt\n");
do {
masked = 1;
if (pending) {
pending = 0;
ar6000_do_irq(hif->func);
/* We may take an interrupt before unmasking and thus
get it pending. In this case, we just loop back. */
}
masked = 0;
}
while (pending);
}
void HIFMaskInterrupt(HIF_DEVICE *hif)
{
struct device *dev = HIFGetOSDevice(hif);
dev_dbg(dev, "HIFMaskInterrupt\n");
/*
* Since sdio_ar6000_irq can also be called from a process context, we
* may conceivably end up racing with it. Thus, we need to wait until
* we can be sure that no concurrent interrupt processing is going on
* before we return.
*
* Note: this may be a bit on the paranoid side - the callers may
* actually be nice enough to disable scheduling. Check later.
*/
masked = 1;
while (in_interrupt)
yield();
}
/* ----- HIF API glue functions -------------------------------------------- */
struct device *HIFGetOSDevice(HIF_DEVICE *hif)
{
return &hif->func->dev;
}
void HIFSetHandle(void *hif_handle, void *handle)
{
HIF_DEVICE *hif = (HIF_DEVICE *) hif_handle;
hif->htc_handle = handle;
}
/* ----- Device configuration (HIF side) ----------------------------------- */
A_STATUS HIFConfigureDevice(HIF_DEVICE *hif,
HIF_DEVICE_CONFIG_OPCODE opcode, void *config, A_UINT32 configLen)
{
struct device *dev = HIFGetOSDevice(hif);
HIF_DEVICE_IRQ_PROCESSING_MODE *ipm_cfg = config;
A_UINT32 *mbs_cfg = config;
int i;
dev_dbg(dev, "HIFConfigureDevice\n");
switch (opcode) {
case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
for (i = 0; i != MBOXES; i++)
mbs_cfg[i] = HIF_MBOX_BLOCK_SIZE;
break;
case HIF_DEVICE_GET_MBOX_ADDR:
for (i = 0; i != MBOXES; i++)
mbs_cfg[i] = HIF_MBOX_START_ADDR(i);
break;
case HIF_DEVICE_GET_IRQ_PROC_MODE:
*ipm_cfg = HIF_DEVICE_IRQ_SYNC_ONLY;
// *ipm_cfg = HIF_DEVICE_IRQ_ASYNC_SYNC;
break;
default:
return A_ERROR;
}
return A_OK;
}
/* ----- Device probe and removal (Linux side) ----------------------------- */
static int ar6000_do_activate(struct hif_device *hif)
{
struct sdio_func *func = hif->func;
struct device *dev = &func->dev;
int ret;
dev_dbg(dev, "ar6000_do_activate\n");
sdio_claim_host(func);
sdio_enable_func(func);
INIT_LIST_HEAD(&hif->queue);
init_waitqueue_head(&hif->wait);
spin_lock_init(&hif->queue_lock);
ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
if (ret < 0) {
dev_err(dev, "sdio_set_block_size returns %d\n", ret);
goto out_enabled;
}
ret = sdio_claim_irq(func, sdio_ar6000_irq);
if (ret) {
dev_err(dev, "sdio_claim_irq returns %d\n", ret);
goto out_enabled;
}
/* Set SDIO_BUS_CD_DISABLE in SDIO_CCCR_IF ? */
#if 0
sdio_f0_writeb(func, SDIO_CCCR_CAP_E4MI, SDIO_CCCR_CAPS, &ret);
if (ret) {
dev_err(dev, "sdio_f0_writeb(SDIO_CCCR_CAPS) returns %d\n",
ret);
goto out_got_irq;
}
#else
if (0) /* avoid warning */
goto out_got_irq;
#endif
sdio_release_host(func);
hif->io_task = kthread_run(io, hif, "ar6000_io");
ret = IS_ERR(hif->io_task);
if (ret) {
dev_err(dev, "kthread_run(ar6000_io): %d\n", ret);
goto out_func_ready;
}
ret = htcCallbacks.deviceInsertedHandler(hif);
if (ret == A_OK)
return 0;
dev_err(dev, "deviceInsertedHandler: %d\n", ret);
ret = kthread_stop(hif->io_task);
if (ret)
dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
out_func_ready:
sdio_claim_host(func);
out_got_irq:
sdio_release_irq(func);
out_enabled:
sdio_disable_func(func);
sdio_release_host(func);
return ret;
}
static void ar6000_do_deactivate(struct hif_device *hif)
{
struct sdio_func *func = hif->func;
struct device *dev = &func->dev;
int ret;
dev_dbg(dev, "ar6000_do_deactivate\n");
if (!hif->active)
return;
if (mutex_trylock(&shutdown_lock)) {
/*
* Funny, Atheros' HIF does this call, but this just puts us in
* a recursion through HTCShutDown/HIFShutDown if unloading the
* module.
*
* However, we need it for suspend/resume. See the comment at
* HIFShutDown, below.
*/
ret = htcCallbacks.deviceRemovedHandler(hif->htc_handle, A_OK);
if (ret != A_OK)
dev_err(dev, "deviceRemovedHandler: %d\n", ret);
mutex_unlock(&shutdown_lock);
}
wait_queue_empty(hif);
ret = kthread_stop(hif->io_task);
if (ret)
dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
sdio_claim_host(func);
sdio_release_irq(func);
sdio_disable_func(func);
sdio_release_host(func);
}
static int ar6000_activate(struct hif_device *hif)
{
int ret = 0;
dev_dbg(&hif->func->dev, "ar6000_activate\n");
mutex_lock(&hif->activate_lock);
if (!hif->active) {
ret = ar6000_do_activate(hif);
if (ret) {
printk(KERN_ERR "%s: Failed to activate %d\n",
__func__, ret);
goto out;
}
hif->active = 1;
}
out:
mutex_unlock(&hif->activate_lock);
return ret;
}
static void ar6000_deactivate(struct hif_device *hif)
{
dev_dbg(&hif->func->dev, "ar6000_deactivate\n");
mutex_lock(&hif->activate_lock);
if (hif->active) {
ar6000_do_deactivate(hif);
hif->active = 0;
}
mutex_unlock(&hif->activate_lock);
}
static int ar6000_rfkill_cb(void *data, int on)
{
struct hif_device *hif = data;
struct sdio_func *func = hif->func;
struct device *dev = &func->dev;
dev_dbg(dev, "ar6000_rfkill_cb: on %d\n", on);
if (on)
return ar6000_activate(hif);
ar6000_deactivate(hif);
return 0;
}
static int sdio_ar6000_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
struct device *dev = &func->dev;
struct hif_device *hif;
int ret = 0;
dev_dbg(dev, "sdio_ar6000_probe\n");
BUG_ON(!htcCallbacks.deviceInsertedHandler);
hif = kzalloc(sizeof(*hif), GFP_KERNEL);
if (!hif)
return -ENOMEM;
sdio_set_drvdata(func, hif);
hif->func = func;
mutex_init(&hif->activate_lock);
hif->active = 0;
if (gta02_wlan_query_rfkill_lock())
ret = ar6000_activate(hif);
if (!ret) {
gta02_wlan_set_rfkill_cb(ar6000_rfkill_cb, hif);
return 0;
}
gta02_wlan_query_rfkill_unlock();
sdio_set_drvdata(func, NULL);
kfree(hif);
return ret;
}
static void sdio_ar6000_remove(struct sdio_func *func)
{
struct device *dev = &func->dev;
HIF_DEVICE *hif = sdio_get_drvdata(func);
dev_dbg(dev, "sdio_ar6000_remove\n");
gta02_wlan_clear_rfkill_cb();
ar6000_deactivate(hif);
sdio_set_drvdata(func, NULL);
kfree(hif);
}
/* ----- Device registration/unregistration (called by HIF) ---------------- */
#define ATHEROS_SDIO_DEVICE(id, offset) \
SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_##id | (offset))
static const struct sdio_device_id sdio_ar6000_ids[] = {
{ ATHEROS_SDIO_DEVICE(AR6002, 0) },
{ ATHEROS_SDIO_DEVICE(AR6002, 0x1) },
{ ATHEROS_SDIO_DEVICE(AR6001, 0x8) },
{ ATHEROS_SDIO_DEVICE(AR6001, 0x9) },
{ ATHEROS_SDIO_DEVICE(AR6001, 0xa) },
{ ATHEROS_SDIO_DEVICE(AR6001, 0xb) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, sdio_ar6000_ids);
static struct sdio_driver sdio_ar6000_driver = {
.probe = sdio_ar6000_probe,
.remove = sdio_ar6000_remove,
.name = "sdio_ar6000",
.id_table = sdio_ar6000_ids,
};
int HIFInit(HTC_CALLBACKS *callbacks)
{
int ret;
BUG_ON(!callbacks);
printk(KERN_DEBUG "HIFInit\n");
htcCallbacks = *callbacks;
ret = sdio_register_driver(&sdio_ar6000_driver);
if (ret) {
printk(KERN_ERR
"sdio_register_driver(sdio_ar6000_driver): %d\n", ret);
return A_ERROR;
}
return 0;
}
/*
* We have four possible call chains here:
*
* System shutdown/reboot:
*
* kernel_restart_prepare ...> device_shutdown ... > s3cmci_shutdown ->
* mmc_remove_host ..> sdio_bus_remove -> sdio_ar6000_remove ->
* ar6000_deactivate -> ar6000_do_deactivate ->
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
*
* This is roughly the same sequence as suspend, described below.
*
* Module removal:
*
* sys_delete_module -> ar6000_cleanup_module -> HTCShutDown ->
* HIFShutDownDevice -> sdio_unregister_driver ...> sdio_bus_remove ->
* sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate
*
* In this case, HIFShutDownDevice must call sdio_unregister_driver to
* notify the driver about its removal. ar6000_do_deactivate must not call
* deviceRemovedHandler, because that would loop back into HIFShutDownDevice.
*
* Suspend:
*
* device_suspend ...> s3cmci_suspend ...> sdio_bus_remove ->
* sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate ->
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
*
* We must call deviceRemovedHandler to inform the ar6k stack that the device
* has been removed. Since HTCTargetRemovedHandler calls back into
* HIFShutDownDevice, we must also prevent the call to
* sdio_unregister_driver, or we'd end up recursing into the SDIO stack,
* eventually deadlocking somewhere.
*
* rfkill:
*
* rfkill_state_store -> rfkill_toggle_radio -> gta02_wlan_toggle_radio ->
* ar6000_rfkill_cb -> ar6000_deactivate -> ar6000_do_deactivate ->
* deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
*
* This is similar to suspend - only the entry point changes.
*/
void HIFShutDownDevice(HIF_DEVICE *hif)
{
/* Beware, HTCShutDown calls us with hif == NULL ! */
if (mutex_trylock(&shutdown_lock)) {
sdio_unregister_driver(&sdio_ar6000_driver);
mutex_unlock(&shutdown_lock);
}
}

View file

@ -0,0 +1,102 @@
/*
* @file: hif_internal.h
*
* @abstract: internal header file for hif layer
*
* @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include <linux/sdio/ctsystem.h>
#include <linux/sdio/sdio_busdriver.h>
#include <linux/sdio/_sdio_defs.h>
#include <linux/sdio/sdio_lib.h>
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "hif.h"
#define MANUFACTURER_ID_AR6001_BASE 0x100
#define MANUFACTURER_ID_AR6002_BASE 0x200
#define FUNCTION_CLASS 0x0
#define MANUFACTURER_CODE 0x271
#define BUS_REQUEST_MAX_NUM 64
#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000
#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20
#define FLAGS_CARD_ENAB 0x02
#define FLAGS_CARD_IRQ_UNMSK 0x04
#define HIF_MBOX_BLOCK_SIZE 128
#define HIF_MBOX_BASE_ADDR 0x800
#define HIF_MBOX_WIDTH 0x800
#define HIF_MBOX0_BLOCK_SIZE 1
#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
#define HIF_MBOX_START_ADDR(mbox) \
HIF_MBOX_BASE_ADDR + mbox * HIF_MBOX_WIDTH
#define HIF_MBOX_END_ADDR(mbox) \
HIF_MBOX_START_ADDR(mbox) + HIF_MBOX_WIDTH - 1
struct hif_device {
SDDEVICE *handle;
void *htc_handle;
OSKERNEL_HELPER insert_helper;
BOOL helper_started;
};
typedef struct target_function_context {
SDFUNCTION function; /* function description of the bus driver */
OS_SEMAPHORE instanceSem; /* instance lock. Unused */
SDLIST instanceList; /* list of instances. Unused */
} TARGET_FUNCTION_CONTEXT;
typedef struct bus_request {
struct bus_request *next;
SDREQUEST *request;
void *context;
} BUS_REQUEST;
BOOL
hifDeviceInserted(SDFUNCTION *function, SDDEVICE *device);
void
hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *device);
SDREQUEST *
hifAllocateDeviceRequest(SDDEVICE *device);
void
hifFreeDeviceRequest(SDREQUEST *request);
void
hifRWCompletionHandler(SDREQUEST *request);
void
hifIRQHandler(void *context);
HIF_DEVICE *
addHifDevice(SDDEVICE *handle);
HIF_DEVICE *
getHifDevice(SDDEVICE *handle);
void
delHifDevice(SDDEVICE *handle);

View file

@ -0,0 +1,991 @@
/*
* AR6K device layer that handles register level I/O
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "AR6Khwreg.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "hif.h"
#include "htc_packet.h"
#include "ar6k.h"
#define MAILBOX_FOR_BLOCK_SIZE 1
extern A_UINT32 resetok;
static A_STATUS DevEnableInterrupts(AR6K_DEVICE *pDev);
static A_STATUS DevDisableInterrupts(AR6K_DEVICE *pDev);
#define LOCK_AR6K(p) A_MUTEX_LOCK(&(p)->Lock);
#define UNLOCK_AR6K(p) A_MUTEX_UNLOCK(&(p)->Lock);
void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket)
{
LOCK_AR6K(pDev);
HTC_PACKET_ENQUEUE(&pDev->RegisterIOList,pPacket);
UNLOCK_AR6K(pDev);
}
HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev)
{
HTC_PACKET *pPacket;
LOCK_AR6K(pDev);
pPacket = HTC_PACKET_DEQUEUE(&pDev->RegisterIOList);
UNLOCK_AR6K(pDev);
return pPacket;
}
A_STATUS DevSetup(AR6K_DEVICE *pDev)
{
A_UINT32 mailboxaddrs[AR6K_MAILBOXES];
A_UINT32 blocksizes[AR6K_MAILBOXES];
A_STATUS status = A_OK;
int i;
AR_DEBUG_ASSERT(AR6K_IRQ_PROC_REGS_SIZE == 16);
AR_DEBUG_ASSERT(AR6K_IRQ_ENABLE_REGS_SIZE == 4);
do {
/* give a handle to HIF for this target */
HIFSetHandle(pDev->HIFDevice, (void *)pDev);
/* initialize our free list of IO packets */
INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList);
A_MUTEX_INIT(&pDev->Lock);
/* get the addresses for all 4 mailboxes */
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
mailboxaddrs, sizeof(mailboxaddrs));
if (status != A_OK) {
AR_DEBUG_ASSERT(FALSE);
break;
}
/* carve up register I/O packets (these are for ASYNC register I/O ) */
for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) {
HTC_PACKET *pIOPacket;
pIOPacket = &pDev->RegIOBuffers[i].HtcPacket;
SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket,
pDev,
pDev->RegIOBuffers[i].Buffer,
AR6K_REG_IO_BUFFER_SIZE,
0); /* don't care */
AR6KFreeIOPacket(pDev,pIOPacket);
}
/* get the address of the mailbox we are using */
pDev->MailboxAddress = mailboxaddrs[HTC_MAILBOX];
/* get the block sizes */
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
blocksizes, sizeof(blocksizes));
if (status != A_OK) {
AR_DEBUG_ASSERT(FALSE);
break;
}
/* note: we actually get the block size of a mailbox other than 0, for SDIO the block
* size on mailbox 0 is artificially set to 1. So we use the block size that is set
* for the other 3 mailboxes */
pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE];
/* must be a power of 2 */
AR_DEBUG_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0);
/* assemble mask, used for padding to a block */
pDev->BlockMask = pDev->BlockSize - 1;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n",
pDev->BlockSize, pDev->MailboxAddress));
pDev->GetPendingEventsFunc = NULL;
/* see if the HIF layer implements the get pending events function */
HIFConfigureDevice(pDev->HIFDevice,
HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
&pDev->GetPendingEventsFunc,
sizeof(pDev->GetPendingEventsFunc));
/* assume we can process HIF interrupt events asynchronously */
pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC;
/* see if the HIF layer overrides this assumption */
HIFConfigureDevice(pDev->HIFDevice,
HIF_DEVICE_GET_IRQ_PROC_MODE,
&pDev->HifIRQProcessingMode,
sizeof(pDev->HifIRQProcessingMode));
switch (pDev->HifIRQProcessingMode) {
case HIF_DEVICE_IRQ_SYNC_ONLY:
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is SYNC ONLY\n"));
break;
case HIF_DEVICE_IRQ_ASYNC_SYNC:
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n"));
break;
default:
AR_DEBUG_ASSERT(FALSE);
}
pDev->HifMaskUmaskRecvEvent = NULL;
/* see if the HIF layer implements the mask/unmask recv events function */
HIFConfigureDevice(pDev->HIFDevice,
HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
&pDev->HifMaskUmaskRecvEvent,
sizeof(pDev->HifMaskUmaskRecvEvent));
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%X , 0x%X\n",
(A_UINT32)pDev->GetPendingEventsFunc, (A_UINT32)pDev->HifMaskUmaskRecvEvent));
status = DevDisableInterrupts(pDev);
} while (FALSE);
if (A_FAILED(status)) {
/* make sure handle is cleared */
HIFSetHandle(pDev->HIFDevice, NULL);
}
return status;
}
static A_STATUS DevEnableInterrupts(AR6K_DEVICE *pDev)
{
A_STATUS status;
AR6K_IRQ_ENABLE_REGISTERS regs;
LOCK_AR6K(pDev);
/* Enable all the interrupts except for the dragon interrupt */
pDev->IrqEnableRegisters.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) |
INT_STATUS_ENABLE_CPU_SET(0x01) |
INT_STATUS_ENABLE_COUNTER_SET(0x01);
if (NULL == pDev->GetPendingEventsFunc) {
pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
} else {
/* The HIF layer provided us with a pending events function which means that
* the detection of pending mbox messages is handled in the HIF layer.
* This is the case for the SPI2 interface.
* In the normal case we enable MBOX interrupts, for the case
* with HIFs that offer this mechanism, we keep these interrupts
* masked */
pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
}
/* Set up the CPU Interrupt Status Register */
pDev->IrqEnableRegisters.cpu_int_status_enable = CPU_INT_STATUS_ENABLE_BIT_SET(0x00);
/* Set up the Error Interrupt Status Register */
pDev->IrqEnableRegisters.error_status_enable =
ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) |
ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01);
/* Set up the Counter Interrupt Status Register (only for debug interrupt to catch fatal errors) */
pDev->IrqEnableRegisters.counter_int_status_enable =
COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK);
/* copy into our temp area */
A_MEMCPY(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
UNLOCK_AR6K(pDev);
/* always synchronous */
status = HIFReadWrite(pDev->HIFDevice,
INT_STATUS_ENABLE_ADDRESS,
&regs.int_status_enable,
AR6K_IRQ_ENABLE_REGS_SIZE,
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
/* Can't write it for some reason */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Failed to update interrupt control registers err: %d\n", status));
}
return status;
}
static A_STATUS DevDisableInterrupts(AR6K_DEVICE *pDev)
{
AR6K_IRQ_ENABLE_REGISTERS regs;
LOCK_AR6K(pDev);
/* Disable all interrupts */
pDev->IrqEnableRegisters.int_status_enable = 0;
pDev->IrqEnableRegisters.cpu_int_status_enable = 0;
pDev->IrqEnableRegisters.error_status_enable = 0;
pDev->IrqEnableRegisters.counter_int_status_enable = 0;
/* copy into our temp area */
A_MEMCPY(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
UNLOCK_AR6K(pDev);
/* always synchronous */
return HIFReadWrite(pDev->HIFDevice,
INT_STATUS_ENABLE_ADDRESS,
&regs.int_status_enable,
AR6K_IRQ_ENABLE_REGS_SIZE,
HIF_WR_SYNC_BYTE_INC,
NULL);
}
/* enable device interrupts */
A_STATUS DevUnmaskInterrupts(AR6K_DEVICE *pDev)
{
/* Unmask the host controller interrupts */
HIFUnMaskInterrupt(pDev->HIFDevice);
return DevEnableInterrupts(pDev);
}
/* disable all device interrupts */
A_STATUS DevMaskInterrupts(AR6K_DEVICE *pDev)
{
A_STATUS status;
status = DevDisableInterrupts(pDev);
if (A_SUCCESS(status)) {
/* Disable the interrupt at the HIF layer */
HIFMaskInterrupt(pDev->HIFDevice);
}
return status;
}
/* callback when our fetch to enable/disable completes */
static void DevDoEnableDisableRecvAsyncHandler(void *Context, HTC_PACKET *pPacket)
{
AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDoEnableDisableRecvAsyncHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
if (A_FAILED(pPacket->Status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" Failed to disable receiver, status:%d \n", pPacket->Status));
}
/* free this IO packet */
AR6KFreeIOPacket(pDev,pPacket);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDoEnableDisableRecvAsyncHandler \n"));
}
/* disable packet reception (used in case the host runs out of buffers)
* this is the "override" method when the HIF reports another methods to
* disable recv events */
static A_STATUS DevDoEnableDisableRecvOverride(AR6K_DEVICE *pDev, A_BOOL EnableRecv, A_BOOL AsyncMode)
{
A_STATUS status = A_OK;
HTC_PACKET *pIOPacket = NULL;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("DevDoEnableDisableRecvOverride: Enable:%d Mode:%d\n",
EnableRecv,AsyncMode));
do {
if (AsyncMode) {
pIOPacket = AR6KAllocIOPacket(pDev);
if (NULL == pIOPacket) {
status = A_NO_MEMORY;
AR_DEBUG_ASSERT(FALSE);
break;
}
/* stick in our completion routine when the I/O operation completes */
pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
pIOPacket->pContext = pDev;
/* call the HIF layer override and do this asynchronously */
status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
pIOPacket);
break;
}
/* if we get here we are doing it synchronously */
status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
NULL);
} while (FALSE);
if (A_FAILED(status) && (pIOPacket != NULL)) {
AR6KFreeIOPacket(pDev,pIOPacket);
}
return status;
}
/* disable packet reception (used in case the host runs out of buffers)
* this is the "normal" method using the interrupt enable registers through
* the host I/F */
static A_STATUS DevDoEnableDisableRecvNormal(AR6K_DEVICE *pDev, A_BOOL EnableRecv, A_BOOL AsyncMode)
{
A_STATUS status = A_OK;
HTC_PACKET *pIOPacket = NULL;
AR6K_IRQ_ENABLE_REGISTERS regs;
/* take the lock to protect interrupt enable shadows */
LOCK_AR6K(pDev);
if (EnableRecv) {
pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
} else {
pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
}
/* copy into our temp area */
A_MEMCPY(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
UNLOCK_AR6K(pDev);
do {
if (AsyncMode) {
pIOPacket = AR6KAllocIOPacket(pDev);
if (NULL == pIOPacket) {
status = A_NO_MEMORY;
AR_DEBUG_ASSERT(FALSE);
break;
}
/* copy values to write to our async I/O buffer */
A_MEMCPY(pIOPacket->pBuffer,&regs,AR6K_IRQ_ENABLE_REGS_SIZE);
/* stick in our completion routine when the I/O operation completes */
pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
pIOPacket->pContext = pDev;
/* write it out asynchronously */
HIFReadWrite(pDev->HIFDevice,
INT_STATUS_ENABLE_ADDRESS,
pIOPacket->pBuffer,
AR6K_IRQ_ENABLE_REGS_SIZE,
HIF_WR_ASYNC_BYTE_INC,
pIOPacket);
break;
}
/* if we get here we are doing it synchronously */
status = HIFReadWrite(pDev->HIFDevice,
INT_STATUS_ENABLE_ADDRESS,
&regs.int_status_enable,
AR6K_IRQ_ENABLE_REGS_SIZE,
HIF_WR_SYNC_BYTE_INC,
NULL);
} while (FALSE);
if (A_FAILED(status) && (pIOPacket != NULL)) {
AR6KFreeIOPacket(pDev,pIOPacket);
}
return status;
}
A_STATUS DevStopRecv(AR6K_DEVICE *pDev, A_BOOL AsyncMode)
{
if (NULL == pDev->HifMaskUmaskRecvEvent) {
return DevDoEnableDisableRecvNormal(pDev,FALSE,AsyncMode);
} else {
return DevDoEnableDisableRecvOverride(pDev,FALSE,AsyncMode);
}
}
A_STATUS DevEnableRecv(AR6K_DEVICE *pDev, A_BOOL AsyncMode)
{
if (NULL == pDev->HifMaskUmaskRecvEvent) {
return DevDoEnableDisableRecvNormal(pDev,TRUE,AsyncMode);
} else {
return DevDoEnableDisableRecvOverride(pDev,TRUE,AsyncMode);
}
}
void DevDumpRegisters(AR6K_IRQ_PROC_REGISTERS *pIrqProcRegs,
AR6K_IRQ_ENABLE_REGISTERS *pIrqEnableRegs)
{
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("\n<------- Register Table -------->\n"));
if (pIrqProcRegs != NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Int Status: 0x%x\n",pIrqProcRegs->host_int_status));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("CPU Int Status: 0x%x\n",pIrqProcRegs->cpu_int_status));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Error Int Status: 0x%x\n",pIrqProcRegs->error_int_status));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Counter Int Status: 0x%x\n",pIrqProcRegs->counter_int_status));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Mbox Frame: 0x%x\n",pIrqProcRegs->mbox_frame));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Rx Lookahead Valid: 0x%x\n",pIrqProcRegs->rx_lookahead_valid));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Rx Lookahead 0: 0x%x\n",pIrqProcRegs->rx_lookahead[0]));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Rx Lookahead 1: 0x%x\n",pIrqProcRegs->rx_lookahead[1]));
}
if (pIrqEnableRegs != NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Int Status Enable: 0x%x\n",pIrqEnableRegs->int_status_enable));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP,
("Counter Int Status Enable: 0x%x\n",pIrqEnableRegs->counter_int_status_enable));
AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("<------------------------------->\n"));
}
}
#ifdef MBOXHW_UNIT_TEST
/* This is a mailbox hardware unit test that must be called in a schedulable context
* This test is very simple, it will send a list of buffers with a counting pattern
* and the target will invert the data and send the message back
*
* the unit test has the following constraints:
*
* The target has at least 8 buffers of 256 bytes each. The host will send
* the following pattern of buffers in rapid succession :
*
* 1 buffer - 128 bytes
* 1 buffer - 256 bytes
* 1 buffer - 512 bytes
* 1 buffer - 1024 bytes
*
* The host will send the buffers to one mailbox and wait for buffers to be reflected
* back from the same mailbox. The target sends the buffers FIFO order.
* Once the final buffer has been received for a mailbox, the next mailbox is tested.
*
*
* Note: To simplifythe test , we assume that the chosen buffer sizes
* will fall on a nice block pad
*
* It is expected that higher-order tests will be written to stress the mailboxes using
* a message-based protocol (with some performance timming) that can create more
* randomness in the packets sent over mailboxes.
*
* */
#define A_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1))
#define BUFFER_BLOCK_PAD 128
#if 0
#define BUFFER1 128
#define BUFFER2 256
#define BUFFER3 512
#define BUFFER4 1024
#endif
#if 1
#define BUFFER1 80
#define BUFFER2 200
#define BUFFER3 444
#define BUFFER4 800
#endif
#define TOTAL_BYTES (A_ROUND_UP_PWR2(BUFFER1,BUFFER_BLOCK_PAD) + \
A_ROUND_UP_PWR2(BUFFER2,BUFFER_BLOCK_PAD) + \
A_ROUND_UP_PWR2(BUFFER3,BUFFER_BLOCK_PAD) + \
A_ROUND_UP_PWR2(BUFFER4,BUFFER_BLOCK_PAD) )
#define TEST_BYTES (BUFFER1 + BUFFER2 + BUFFER3 + BUFFER4)
#define TEST_CREDITS_RECV_TIMEOUT 100
static A_UINT8 g_Buffer[TOTAL_BYTES];
static A_UINT32 g_MailboxAddrs[AR6K_MAILBOXES];
static A_UINT32 g_BlockSizes[AR6K_MAILBOXES];
#define BUFFER_PROC_LIST_DEPTH 4
typedef struct _BUFFER_PROC_LIST{
A_UINT8 *pBuffer;
A_UINT32 length;
}BUFFER_PROC_LIST;
#define PUSH_BUFF_PROC_ENTRY(pList,len,pCurrpos) \
{ \
(pList)->pBuffer = (pCurrpos); \
(pList)->length = (len); \
(pCurrpos) += (len); \
(pList)++; \
}
/* a simple and crude way to send different "message" sizes */
static void AssembleBufferList(BUFFER_PROC_LIST *pList)
{
A_UINT8 *pBuffer = g_Buffer;
#if BUFFER_PROC_LIST_DEPTH < 4
#error "Buffer processing list depth is not deep enough!!"
#endif
PUSH_BUFF_PROC_ENTRY(pList,BUFFER1,pBuffer);
PUSH_BUFF_PROC_ENTRY(pList,BUFFER2,pBuffer);
PUSH_BUFF_PROC_ENTRY(pList,BUFFER3,pBuffer);
PUSH_BUFF_PROC_ENTRY(pList,BUFFER4,pBuffer);
}
#define FILL_ZERO TRUE
#define FILL_COUNTING FALSE
static void InitBuffers(A_BOOL Zero)
{
A_UINT16 *pBuffer16 = (A_UINT16 *)g_Buffer;
int i;
/* fill buffer with 16 bit counting pattern or zeros */
for (i = 0; i < (TOTAL_BYTES / 2) ; i++) {
if (!Zero) {
pBuffer16[i] = (A_UINT16)i;
} else {
pBuffer16[i] = 0;
}
}
}
static A_BOOL CheckOneBuffer(A_UINT16 *pBuffer16, int Length)
{
int i;
A_UINT16 startCount;
A_BOOL success = TRUE;
/* get the starting count */
startCount = pBuffer16[0];
/* invert it, this is the expected value */
startCount = ~startCount;
/* scan the buffer and verify */
for (i = 0; i < (Length / 2) ; i++,startCount++) {
/* target will invert all the data */
if ((A_UINT16)pBuffer16[i] != (A_UINT16)~startCount) {
success = FALSE;
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid Data Got:0x%X, Expecting:0x%X (offset:%d, total:%d) \n",
pBuffer16[i], ((A_UINT16)~startCount), i, Length));
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("0x%X 0x%X 0x%X 0x%X \n",
pBuffer16[i], pBuffer16[i + 1], pBuffer16[i + 2],pBuffer16[i+3]));
break;
}
}
return success;
}
static A_BOOL CheckBuffers(void)
{
int i;
A_BOOL success = TRUE;
BUFFER_PROC_LIST checkList[BUFFER_PROC_LIST_DEPTH];
/* assemble the list */
AssembleBufferList(checkList);
/* scan the buffers and verify */
for (i = 0; i < BUFFER_PROC_LIST_DEPTH ; i++) {
success = CheckOneBuffer((A_UINT16 *)checkList[i].pBuffer, checkList[i].length);
if (!success) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer : 0x%X, Length:%d failed verify \n",
(A_UINT32)checkList[i].pBuffer, checkList[i].length));
break;
}
}
return success;
}
/* find the end marker for the last buffer we will be sending */
static A_UINT16 GetEndMarker(void)
{
A_UINT8 *pBuffer;
BUFFER_PROC_LIST checkList[BUFFER_PROC_LIST_DEPTH];
/* fill up buffers with the normal counting pattern */
InitBuffers(FILL_COUNTING);
/* assemble the list we will be sending down */
AssembleBufferList(checkList);
/* point to the last 2 bytes of the last buffer */
pBuffer = &(checkList[BUFFER_PROC_LIST_DEPTH - 1].pBuffer[(checkList[BUFFER_PROC_LIST_DEPTH - 1].length) - 2]);
/* the last count in the last buffer is the marker */
return (A_UINT16)pBuffer[0] | ((A_UINT16)pBuffer[1] << 8);
}
#define ATH_PRINT_OUT_ZONE ATH_DEBUG_ERR
/* send the ordered buffers to the target */
static A_STATUS SendBuffers(AR6K_DEVICE *pDev, int mbox)
{
A_STATUS status = A_OK;
A_UINT32 request = HIF_WR_SYNC_BLOCK_INC;
BUFFER_PROC_LIST sendList[BUFFER_PROC_LIST_DEPTH];
int i;
int totalBytes = 0;
int paddedLength;
int totalwPadding = 0;
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sending buffers on mailbox : %d \n",mbox));
/* fill buffer with counting pattern */
InitBuffers(FILL_COUNTING);
/* assemble the order in which we send */
AssembleBufferList(sendList);
for (i = 0; i < BUFFER_PROC_LIST_DEPTH; i++) {
/* we are doing block transfers, so we need to pad everything to a block size */
paddedLength = (sendList[i].length + (g_BlockSizes[mbox] - 1)) &
(~(g_BlockSizes[mbox] - 1));
/* send each buffer synchronously */
status = HIFReadWrite(pDev->HIFDevice,
g_MailboxAddrs[mbox],
sendList[i].pBuffer,
paddedLength,
request,
NULL);
if (status != A_OK) {
break;
}
totalBytes += sendList[i].length;
totalwPadding += paddedLength;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sent %d bytes (%d padded bytes) to mailbox : %d \n",totalBytes,totalwPadding,mbox));
return status;
}
/* poll the mailbox credit counter until we get a credit or timeout */
static A_STATUS GetCredits(AR6K_DEVICE *pDev, int mbox, int *pCredits)
{
A_STATUS status = A_OK;
int timeout = TEST_CREDITS_RECV_TIMEOUT;
A_UINT8 credits = 0;
A_UINT32 address;
while (TRUE) {
/* Read the counter register to get credits, this auto-decrements */
address = COUNT_DEC_ADDRESS + (AR6K_MAILBOXES + mbox) * 4;
status = HIFReadWrite(pDev->HIFDevice, address, &credits, sizeof(credits),
HIF_RD_SYNC_BYTE_FIX, NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Unable to decrement the command credit count register (mbox=%d)\n",mbox));
status = A_ERROR;
break;
}
if (credits) {
break;
}
timeout--;
if (timeout <= 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" Timeout reading credit registers (mbox=%d, address:0x%X) \n",mbox,address));
status = A_ERROR;
break;
}
/* delay a little, target may not be ready */
msleep(1000);
}
if (status == A_OK) {
*pCredits = credits;
}
return status;
}
/* wait for the buffers to come back */
static A_STATUS RecvBuffers(AR6K_DEVICE *pDev, int mbox)
{
A_STATUS status = A_OK;
A_UINT32 request = HIF_RD_SYNC_BLOCK_INC;
BUFFER_PROC_LIST recvList[BUFFER_PROC_LIST_DEPTH];
int curBuffer;
int credits;
int i;
int totalBytes = 0;
int paddedLength;
int totalwPadding = 0;
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for buffers on mailbox : %d \n",mbox));
/* zero the buffers */
InitBuffers(FILL_ZERO);
/* assemble the order in which we should receive */
AssembleBufferList(recvList);
curBuffer = 0;
while (curBuffer < BUFFER_PROC_LIST_DEPTH) {
/* get number of buffers that have been completed, this blocks
* until we get at least 1 credit or it times out */
status = GetCredits(pDev, mbox, &credits);
if (status != A_OK) {
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got %d messages on mailbox : %d \n",credits, mbox));
/* get all the buffers that are sitting on the queue */
for (i = 0; i < credits; i++) {
AR_DEBUG_ASSERT(curBuffer < BUFFER_PROC_LIST_DEPTH);
/* recv the current buffer synchronously, the buffers should come back in
* order... with padding applied by the target */
paddedLength = (recvList[curBuffer].length + (g_BlockSizes[mbox] - 1)) &
(~(g_BlockSizes[mbox] - 1));
status = HIFReadWrite(pDev->HIFDevice,
g_MailboxAddrs[mbox],
recvList[curBuffer].pBuffer,
paddedLength,
request,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to read %d bytes on mailbox:%d : address:0x%X \n",
recvList[curBuffer].length, mbox, g_MailboxAddrs[mbox]));
break;
}
totalwPadding += paddedLength;
totalBytes += recvList[curBuffer].length;
curBuffer++;
}
if (status != A_OK) {
break;
}
/* go back and get some more */
credits = 0;
}
if (totalBytes != TEST_BYTES) {
AR_DEBUG_ASSERT(FALSE);
} else {
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got all buffers on mbox:%d total recv :%d (w/Padding : %d) \n",
mbox, totalBytes, totalwPadding));
}
return status;
}
static A_STATUS DoOneMboxHWTest(AR6K_DEVICE *pDev, int mbox)
{
A_STATUS status;
do {
/* send out buffers */
status = SendBuffers(pDev,mbox);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Sending buffers Failed : %d mbox:%d\n",status,mbox));
break;
}
/* go get them, this will block */
status = RecvBuffers(pDev, mbox);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Recv buffers Failed : %d mbox:%d\n",status,mbox));
break;
}
/* check the returned data patterns */
if (!CheckBuffers()) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer Verify Failed : mbox:%d\n",mbox));
status = A_ERROR;
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" Send/Recv success! mailbox : %d \n",mbox));
} while (FALSE);
return status;
}
/* here is where the test starts */
A_STATUS DoMboxHWTest(AR6K_DEVICE *pDev)
{
int i;
A_STATUS status;
int credits = 0;
A_UINT8 params[4];
int numBufs;
int bufferSize;
A_UINT16 temp;
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest START - \n"));
do {
/* get the addresses for all 4 mailboxes */
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
g_MailboxAddrs, sizeof(g_MailboxAddrs));
if (status != A_OK) {
AR_DEBUG_ASSERT(FALSE);
break;
}
/* get the block sizes */
status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
g_BlockSizes, sizeof(g_BlockSizes));
if (status != A_OK) {
AR_DEBUG_ASSERT(FALSE);
break;
}
/* note, the HIF layer usually reports mbox 0 to have a block size of
* 1, but our test wants to run in block-mode for all mailboxes, so we treat all mailboxes
* the same. */
g_BlockSizes[0] = g_BlockSizes[1];
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Block Size to use: %d \n",g_BlockSizes[0]));
if (g_BlockSizes[1] > BUFFER_BLOCK_PAD) {
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("%d Block size is too large for buffer pad %d\n",
g_BlockSizes[1], BUFFER_BLOCK_PAD));
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for target.... \n"));
/* the target lets us know it is ready by giving us 1 credit on
* mailbox 0 */
status = GetCredits(pDev, 0, &credits);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait for target ready \n"));
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Target is ready ...\n"));
/* read the first 4 scratch registers */
status = HIFReadWrite(pDev->HIFDevice,
SCRATCH_ADDRESS,
params,
4,
HIF_RD_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait get parameters \n"));
break;
}
numBufs = params[0];
bufferSize = (int)(((A_UINT16)params[2] << 8) | (A_UINT16)params[1]);
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE,
("Target parameters: bufs per mailbox:%d, buffer size:%d bytes (total space: %d, minimum required space (w/padding): %d) \n",
numBufs, bufferSize, (numBufs * bufferSize), TOTAL_BYTES));
if ((numBufs * bufferSize) < TOTAL_BYTES) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Not Enough buffer space to run test! need:%d, got:%d \n",
TOTAL_BYTES, (numBufs*bufferSize)));
status = A_ERROR;
break;
}
temp = GetEndMarker();
status = HIFReadWrite(pDev->HIFDevice,
SCRATCH_ADDRESS + 4,
(A_UINT8 *)&temp,
2,
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write end marker \n"));
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("End Marker: 0x%X \n",temp));
temp = (A_UINT16)g_BlockSizes[1];
/* convert to a mask */
temp = temp - 1;
status = HIFReadWrite(pDev->HIFDevice,
SCRATCH_ADDRESS + 6,
(A_UINT8 *)&temp,
2,
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write block mask \n"));
break;
}
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Set Block Mask: 0x%X \n",temp));
/* execute the test on each mailbox */
for (i = 0; i < AR6K_MAILBOXES; i++) {
status = DoOneMboxHWTest(pDev, i);
if (status != A_OK) {
break;
}
}
} while (FALSE);
if (status == A_OK) {
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - SUCCESS! - \n"));
} else {
AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - FAILED! - \n"));
}
/* don't let HTC_Start continue, the target is actually not running any HTC code */
return A_ERROR;
}
#endif

View file

@ -0,0 +1,191 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef AR6K_H_
#define AR6K_H_
#define AR6K_MAILBOXES 4
/* HTC runs over mailbox 0 */
#define HTC_MAILBOX 0
#define AR6K_TARGET_DEBUG_INTR_MASK 0x01
#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
INT_STATUS_ENABLE_CPU_MASK | \
INT_STATUS_ENABLE_COUNTER_MASK)
//#define MBOXHW_UNIT_TEST 1
#include "athstartpack.h"
typedef PREPACK struct _AR6K_IRQ_PROC_REGISTERS {
A_UINT8 host_int_status;
A_UINT8 cpu_int_status;
A_UINT8 error_int_status;
A_UINT8 counter_int_status;
A_UINT8 mbox_frame;
A_UINT8 rx_lookahead_valid;
A_UINT8 hole[2];
A_UINT32 rx_lookahead[2];
} POSTPACK AR6K_IRQ_PROC_REGISTERS;
#define AR6K_IRQ_PROC_REGS_SIZE sizeof(AR6K_IRQ_PROC_REGISTERS)
typedef PREPACK struct _AR6K_IRQ_ENABLE_REGISTERS {
A_UINT8 int_status_enable;
A_UINT8 cpu_int_status_enable;
A_UINT8 error_status_enable;
A_UINT8 counter_int_status_enable;
} POSTPACK AR6K_IRQ_ENABLE_REGISTERS;
#include "athendpack.h"
#define AR6K_IRQ_ENABLE_REGS_SIZE sizeof(AR6K_IRQ_ENABLE_REGISTERS)
#define AR6K_REG_IO_BUFFER_SIZE 32
#define AR6K_MAX_REG_IO_BUFFERS 8
/* buffers for ASYNC I/O */
typedef struct AR6K_ASYNC_REG_IO_BUFFER {
HTC_PACKET HtcPacket; /* we use an HTC packet as a wrapper for our async register-based I/O */
A_UINT8 Buffer[AR6K_REG_IO_BUFFER_SIZE];
} AR6K_ASYNC_REG_IO_BUFFER;
typedef struct _AR6K_DEVICE {
A_MUTEX_T Lock;
AR6K_IRQ_PROC_REGISTERS IrqProcRegisters;
AR6K_IRQ_ENABLE_REGISTERS IrqEnableRegisters;
void *HIFDevice;
A_UINT32 BlockSize;
A_UINT32 BlockMask;
A_UINT32 MailboxAddress;
HIF_PENDING_EVENTS_FUNC GetPendingEventsFunc;
void *HTCContext;
HTC_PACKET_QUEUE RegisterIOList;
AR6K_ASYNC_REG_IO_BUFFER RegIOBuffers[AR6K_MAX_REG_IO_BUFFERS];
void (*TargetFailureCallback)(void *Context);
A_STATUS (*MessagePendingCallback)(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc);
HIF_DEVICE_IRQ_PROCESSING_MODE HifIRQProcessingMode;
HIF_MASK_UNMASK_RECV_EVENT HifMaskUmaskRecvEvent;
} AR6K_DEVICE;
#define IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pDev) ((pDev)->HifIRQProcessingMode != HIF_DEVICE_IRQ_SYNC_ONLY)
A_STATUS DevSetup(AR6K_DEVICE *pDev);
A_STATUS DevUnmaskInterrupts(AR6K_DEVICE *pDev);
A_STATUS DevMaskInterrupts(AR6K_DEVICE *pDev);
A_STATUS DevPollMboxMsgRecv(AR6K_DEVICE *pDev,
A_UINT32 *pLookAhead,
int TimeoutMS);
A_STATUS DevRWCompletionHandler(void *context, A_STATUS status);
A_STATUS DevDsrHandler(void *context);
A_STATUS DevCheckPendingRecvMsgsAsync(void *context);
void DevDumpRegisters(AR6K_IRQ_PROC_REGISTERS *pIrqProcRegs,
AR6K_IRQ_ENABLE_REGISTERS *pIrqEnableRegs);
#define DEV_STOP_RECV_ASYNC TRUE
#define DEV_STOP_RECV_SYNC FALSE
#define DEV_ENABLE_RECV_ASYNC TRUE
#define DEV_ENABLE_RECV_SYNC FALSE
A_STATUS DevStopRecv(AR6K_DEVICE *pDev, A_BOOL ASyncMode);
A_STATUS DevEnableRecv(AR6K_DEVICE *pDev, A_BOOL ASyncMode);
static INLINE A_STATUS DevSendPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 SendLength) {
A_UINT32 paddedLength;
A_BOOL sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
A_STATUS status;
/* adjust the length to be a multiple of block size if appropriate */
paddedLength = (SendLength + (pDev->BlockMask)) &
(~(pDev->BlockMask));
#if 0 // BufferLength may not be set in , fix this...
if (paddedLength > pPacket->BufferLength) {
AR_DEBUG_ASSERT(FALSE);
if (pPacket->Completion != NULL) {
COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
}
return A_EINVAL;
}
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("DevSendPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n",
paddedLength,
pDev->MailboxAddress,
sync ? "SYNC" : "ASYNC"));
status = HIFReadWrite(pDev->HIFDevice,
pDev->MailboxAddress,
pPacket->pBuffer,
paddedLength, /* the padded length */
sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC,
sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
if (sync) {
pPacket->Status = status;
}
return status;
}
static INLINE A_STATUS DevRecvPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 RecvLength) {
A_UINT32 paddedLength;
A_STATUS status;
A_BOOL sync = (pPacket->Completion == NULL) ? TRUE : FALSE;
/* adjust the length to be a multiple of block size if appropriate */
paddedLength = (RecvLength + (pDev->BlockMask)) &
(~(pDev->BlockMask));
if (paddedLength > pPacket->BufferLength) {
AR_DEBUG_ASSERT(FALSE);
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("DevRecvPacket, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n",
paddedLength,RecvLength,pPacket->BufferLength));
if (pPacket->Completion != NULL) {
COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
}
return A_EINVAL;
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("DevRecvPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n",
paddedLength,
pDev->MailboxAddress,
sync ? "SYNC" : "ASYNC"));
status = HIFReadWrite(pDev->HIFDevice,
pDev->MailboxAddress,
pPacket->pBuffer,
paddedLength,
sync ? HIF_RD_SYNC_BLOCK_INC : HIF_RD_ASYNC_BLOCK_INC,
sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
if (sync) {
pPacket->Status = status;
}
return status;
}
#ifdef MBOXHW_UNIT_TEST
A_STATUS DoMboxHWTest(AR6K_DEVICE *pDev);
#endif
#endif /*AR6K_H_*/

View file

@ -0,0 +1,638 @@
/*
* AR6K Driver layer event handling (i.e. interrupts, message polling)
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "AR6Khwreg.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "hif.h"
#include "htc_packet.h"
#include "ar6k.h"
extern void AR6KFreeIOPacket(AR6K_DEVICE *pDev, HTC_PACKET *pPacket);
extern HTC_PACKET *AR6KAllocIOPacket(AR6K_DEVICE *pDev);
static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev);
#define DELAY_PER_INTERVAL_MS 10 /* 10 MS delay per polling interval */
/* completion routine for ALL HIF layer async I/O */
A_STATUS DevRWCompletionHandler(void *context, A_STATUS status)
{
HTC_PACKET *pPacket = (HTC_PACKET *)context;
COMPLETE_HTC_PACKET(pPacket,status);
return A_OK;
}
/* mailbox recv message polling */
A_STATUS DevPollMboxMsgRecv(AR6K_DEVICE *pDev,
A_UINT32 *pLookAhead,
int TimeoutMS)
{
A_STATUS status = A_OK;
int timeout = TimeoutMS/DELAY_PER_INTERVAL_MS;
AR_DEBUG_ASSERT(timeout > 0);
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevPollMboxMsgRecv \n"));
while (TRUE) {
if (pDev->GetPendingEventsFunc != NULL)
{
HIF_PENDING_EVENTS_INFO events;
/* the HIF layer uses a special mechanism to get events, do this
* synchronously */
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
&events,
NULL);
if (A_FAILED(status))
{
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get pending events \n"));
break;
}
if (events.Events & HIF_RECV_MSG_AVAIL)
{
/* there is a message available, the lookahead should be valid now */
*pLookAhead = events.LookAhead;
break;
}
}
else
{
/* this is the standard HIF way.... */
/* load the register table */
status = HIFReadWrite(pDev->HIFDevice,
HOST_INT_STATUS_ADDRESS,
(A_UINT8 *)&pDev->IrqProcRegisters,
AR6K_IRQ_PROC_REGS_SIZE,
HIF_RD_SYNC_BYTE_INC,
NULL);
if (A_FAILED(status))
{
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to read register table \n"));
break;
}
/* check for MBOX data and valid lookahead */
if (pDev->IrqProcRegisters.host_int_status & (1 << HTC_MAILBOX))
{
if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX))
{
/* mailbox has a message and the look ahead is valid */
*pLookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
break;
}
}
}
timeout--;
if (timeout <= 0)
{
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout waiting for recv message \n"));
status = A_ERROR;
/* check if the target asserted */
if ( pDev->IrqProcRegisters.counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
/* target signaled an assert, process this pending interrupt
* this will call the target failure handler */
DevServiceDebugInterrupt(pDev);
}
break;
}
/* delay a little */
msleep(DELAY_PER_INTERVAL_MS);
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Retry Mbox Poll : %d \n",timeout));
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevPollMboxMsgRecv \n"));
return status;
}
static A_STATUS DevServiceCPUInterrupt(AR6K_DEVICE *pDev)
{
A_STATUS status;
A_UINT8 cpu_int_status;
A_UINT8 regBuffer[4];
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n"));
cpu_int_status = pDev->IrqProcRegisters.cpu_int_status &
pDev->IrqEnableRegisters.cpu_int_status_enable;
AR_DEBUG_ASSERT(cpu_int_status);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
cpu_int_status));
/* Clear the interrupt */
pDev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; /* W1C */
/* set up the register transfer buffer to hit the register 4 times , this is done
* to make the access 4-byte aligned to mitigate issues with host bus interconnects that
* restrict bus transfer lengths to be a multiple of 4-bytes */
/* set W1C value to clear the interrupt, this hits the register first */
regBuffer[0] = cpu_int_status;
/* the remaining 4 values are set to zero which have no-effect */
regBuffer[1] = 0;
regBuffer[2] = 0;
regBuffer[3] = 0;
status = HIFReadWrite(pDev->HIFDevice,
CPU_INT_STATUS_ADDRESS,
regBuffer,
4,
HIF_WR_SYNC_BYTE_FIX,
NULL);
AR_DEBUG_ASSERT(status == A_OK);
return status;
}
static A_STATUS DevServiceErrorInterrupt(AR6K_DEVICE *pDev)
{
A_STATUS status;
A_UINT8 error_int_status;
A_UINT8 regBuffer[4];
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error Interrupt\n"));
error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F;
AR_DEBUG_ASSERT(error_int_status);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
error_int_status));
if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
/* Wakeup */
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n"));
}
if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
/* Rx Underflow */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n"));
}
if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
/* Tx Overflow */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n"));
}
/* Clear the interrupt */
pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */
/* set up the register transfer buffer to hit the register 4 times , this is done
* to make the access 4-byte aligned to mitigate issues with host bus interconnects that
* restrict bus transfer lengths to be a multiple of 4-bytes */
/* set W1C value to clear the interrupt, this hits the register first */
regBuffer[0] = error_int_status;
/* the remaining 4 values are set to zero which have no-effect */
regBuffer[1] = 0;
regBuffer[2] = 0;
regBuffer[3] = 0;
status = HIFReadWrite(pDev->HIFDevice,
ERROR_INT_STATUS_ADDRESS,
regBuffer,
4,
HIF_WR_SYNC_BYTE_FIX,
NULL);
AR_DEBUG_ASSERT(status == A_OK);
return status;
}
static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev)
{
A_UINT32 dummy;
A_STATUS status;
/* Send a target failure event to the application */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n"));
if (pDev->TargetFailureCallback != NULL) {
pDev->TargetFailureCallback(pDev->HTCContext);
}
/* clear the interrupt , the debug error interrupt is
* counter 0 */
/* read counter to clear interrupt */
status = HIFReadWrite(pDev->HIFDevice,
COUNT_DEC_ADDRESS,
(A_UINT8 *)&dummy,
4,
HIF_RD_SYNC_BYTE_INC,
NULL);
AR_DEBUG_ASSERT(status == A_OK);
return status;
}
static A_STATUS DevServiceCounterInterrupt(AR6K_DEVICE *pDev)
{
A_UINT8 counter_int_status;
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
counter_int_status = pDev->IrqProcRegisters.counter_int_status &
pDev->IrqEnableRegisters.counter_int_status_enable;
AR_DEBUG_ASSERT(counter_int_status);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
counter_int_status));
/* Check if the debug interrupt is pending */
if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
return DevServiceDebugInterrupt(pDev);
}
return A_OK;
}
/* callback when our fetch to get interrupt status registers completes */
static void DevGetEventAsyncHandler(void *Context, HTC_PACKET *pPacket)
{
AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context;
A_UINT32 lookAhead = 0;
A_BOOL otherInts = FALSE;
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
do {
if (A_FAILED(pPacket->Status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" GetEvents I/O request failed, status:%d \n", pPacket->Status));
/* bail out, don't unmask HIF interrupt */
break;
}
if (pDev->GetPendingEventsFunc != NULL) {
/* the HIF layer collected the information for us */
HIF_PENDING_EVENTS_INFO *pEvents = (HIF_PENDING_EVENTS_INFO *)pPacket->pBuffer;
if (pEvents->Events & HIF_RECV_MSG_AVAIL) {
lookAhead = pEvents->LookAhead;
if (0 == lookAhead) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n"));
}
}
if (pEvents->Events & HIF_OTHER_EVENTS) {
otherInts = TRUE;
}
} else {
/* standard interrupt table handling.... */
AR6K_IRQ_PROC_REGISTERS *pReg = (AR6K_IRQ_PROC_REGISTERS *)pPacket->pBuffer;
A_UINT8 host_int_status;
host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable;
if (host_int_status & (1 << HTC_MAILBOX)) {
host_int_status &= ~(1 << HTC_MAILBOX);
if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) {
/* mailbox has a message and the look ahead is valid */
lookAhead = pReg->rx_lookahead[HTC_MAILBOX];
if (0 == lookAhead) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n"));
}
}
}
if (host_int_status) {
/* there are other interrupts to handle */
otherInts = TRUE;
}
}
if (otherInts || (lookAhead == 0)) {
/* if there are other interrupts to process, we cannot do this in the async handler so
* ack the interrupt which will cause our sync handler to run again
* if however there are no more messages, we can now ack the interrupt */
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
(" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n",
otherInts, lookAhead));
HIFAckInterrupt(pDev->HIFDevice);
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
(" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n",
lookAhead));
/* lookahead is non-zero and there are no other interrupts to service,
* go get the next message */
pDev->MessagePendingCallback(pDev->HTCContext, lookAhead, NULL);
}
} while (FALSE);
/* free this IO packet */
AR6KFreeIOPacket(pDev,pPacket);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n"));
}
/* called by the HTC layer when it wants us to check if the device has any more pending
* recv messages, this starts off a series of async requests to read interrupt registers */
A_STATUS DevCheckPendingRecvMsgsAsync(void *context)
{
AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
A_STATUS status = A_OK;
HTC_PACKET *pIOPacket;
/* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can
* cause us to switch contexts */
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%X)\n", (A_UINT32)pDev));
do {
if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
/* break the async processing chain right here, no need to continue.
* The DevDsrHandler() will handle things in a loop when things are driven
* synchronously */
break;
}
/* first allocate one of our HTC packets we created for async I/O
* we reuse HTC packet definitions so that we can use the completion mechanism
* in DevRWCompletionHandler() */
pIOPacket = AR6KAllocIOPacket(pDev);
if (NULL == pIOPacket) {
/* there should be only 1 asynchronous request out at a time to read these registers
* so this should actually never happen */
status = A_NO_MEMORY;
AR_DEBUG_ASSERT(FALSE);
break;
}
/* stick in our completion routine when the I/O operation completes */
pIOPacket->Completion = DevGetEventAsyncHandler;
pIOPacket->pContext = pDev;
if (pDev->GetPendingEventsFunc) {
/* HIF layer has it's own mechanism, pass the IO to it.. */
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
(HIF_PENDING_EVENTS_INFO *)pIOPacket->pBuffer,
pIOPacket);
} else {
/* standard way, read the interrupt register table asynchronously again */
status = HIFReadWrite(pDev->HIFDevice,
HOST_INT_STATUS_ADDRESS,
pIOPacket->pBuffer,
AR6K_IRQ_PROC_REGS_SIZE,
HIF_RD_ASYNC_BYTE_INC,
pIOPacket);
}
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n"));
} while (FALSE);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n"));
return status;
}
/* process pending interrupts synchronously */
static A_STATUS ProcessPendingIRQs(AR6K_DEVICE *pDev, A_BOOL *pDone, A_BOOL *pASyncProcessing)
{
A_STATUS status = A_OK;
A_UINT8 host_int_status = 0;
A_UINT32 lookAhead = 0;
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%X)\n", (A_UINT32)pDev));
/*** NOTE: the HIF implementation guarantees that the context of this call allows
* us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
* can block or switch thread/task ontexts.
* This is a fully schedulable context.
* */
do {
if (pDev->GetPendingEventsFunc != NULL) {
HIF_PENDING_EVENTS_INFO events;
/* the HIF layer uses a special mechanism to get events
* get this synchronously */
status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
&events,
NULL);
if (A_FAILED(status)) {
break;
}
if (events.Events & HIF_RECV_MSG_AVAIL) {
lookAhead = events.LookAhead;
if (0 == lookAhead) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
}
}
if (!(events.Events & HIF_OTHER_EVENTS) ||
!(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
/* no need to read the register table, no other interesting interrupts.
* Some interfaces (like SPI) can shadow interrupt sources without
* requiring the host to do a full table read */
break;
}
/* otherwise fall through and read the register table */
}
/*
* Read the first 28 bytes of the HTC register table. This will yield us
* the value of different int status registers and the lookahead
* registers.
* length = sizeof(int_status) + sizeof(cpu_int_status) +
* sizeof(error_int_status) + sizeof(counter_int_status) +
* sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
* sizeof(hole) + sizeof(rx_lookahead) +
* sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
* sizeof(error_status_enable) +
* sizeof(counter_int_status_enable);
*
*/
status = HIFReadWrite(pDev->HIFDevice,
HOST_INT_STATUS_ADDRESS,
(A_UINT8 *)&pDev->IrqProcRegisters,
AR6K_IRQ_PROC_REGS_SIZE,
HIF_RD_SYNC_BYTE_INC,
NULL);
if (A_FAILED(status)) {
break;
}
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
DevDumpRegisters(&pDev->IrqProcRegisters,
&pDev->IrqEnableRegisters);
}
/* Update only those registers that are enabled */
host_int_status = pDev->IrqProcRegisters.host_int_status &
pDev->IrqEnableRegisters.int_status_enable;
if (NULL == pDev->GetPendingEventsFunc) {
/* only look at mailbox status if the HIF layer did not provide this function,
* on some HIF interfaces reading the RX lookahead is not valid to do */
if (host_int_status & (1 << HTC_MAILBOX)) {
/* mask out pending mailbox value, we use "lookAhead" as the real flag for
* mailbox processing below */
host_int_status &= ~(1 << HTC_MAILBOX);
if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
/* mailbox has a message and the look ahead is valid */
lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
if (0 == lookAhead) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
}
}
}
} else {
/* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
host_int_status &= ~(1 << HTC_MAILBOX);
}
} while (FALSE);
do {
/* did the interrupt status fetches succeed? */
if (A_FAILED(status)) {
break;
}
if ((0 == host_int_status) && (0 == lookAhead)) {
/* nothing to process, the caller can use this to break out of a loop */
*pDone = TRUE;
break;
}
if (lookAhead != 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
/* Mailbox Interrupt, the HTC layer may issue async requests to empty the
* mailbox...
* When emptying the recv mailbox we use the async handler above called from the
* completion routine of the callers read request. This can improve performance
* by reducing context switching when we rapidly pull packets */
status = pDev->MessagePendingCallback(pDev->HTCContext, lookAhead, pASyncProcessing);
if (A_FAILED(status)) {
break;
}
}
/* now handle the rest of them */
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
(" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
host_int_status));
if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
/* CPU Interrupt */
status = DevServiceCPUInterrupt(pDev);
if (A_FAILED(status)){
break;
}
}
if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
/* Error Interrupt */
status = DevServiceErrorInterrupt(pDev);
if (A_FAILED(status)){
break;
}
}
if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
/* Counter Interrupt */
status = DevServiceCounterInterrupt(pDev);
if (A_FAILED(status)){
break;
}
}
} while (FALSE);
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
*pDone, *pASyncProcessing, status));
return status;
}
/* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/
A_STATUS DevDsrHandler(void *context)
{
AR6K_DEVICE *pDev = (AR6K_DEVICE *)context;
A_STATUS status = A_OK;
A_BOOL done = FALSE;
A_BOOL asyncProc = FALSE;
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%X)\n", (A_UINT32)pDev));
while (!done) {
status = ProcessPendingIRQs(pDev, &done, &asyncProc);
if (A_FAILED(status)) {
break;
}
if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
/* the HIF layer does not allow async IRQ processing, override the asyncProc flag */
asyncProc = FALSE;
/* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers.
* this has a nice side effect of blocking us until all async read requests are completed.
* This behavior is required on some HIF implementations that do not allow ASYNC
* processing in interrupt handlers (like Windows CE) */
}
if (asyncProc) {
/* the function performed some async I/O for performance, we
need to exit the ISR immediately, the check below will prevent the interrupt from being
Ack'd while we handle it asynchronously */
break;
}
}
if (A_SUCCESS(status) && !asyncProc) {
/* Ack the interrupt only if :
* 1. we did not get any errors in processing interrupts
* 2. there are no outstanding async processing requests */
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n"));
HIFAckInterrupt(pDev->HIFDevice);
}
AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n"));
return A_OK;
}

View file

@ -0,0 +1,508 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "htc_internal.h"
static HTC_INIT_INFO HTCInitInfo = {NULL,NULL,NULL};
static A_BOOL HTCInitialized = FALSE;
static A_STATUS HTCTargetInsertedHandler(void *hif_handle);
static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status);
static void HTCReportFailure(void *Context);
/* Initializes the HTC layer */
A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo)
{
HTC_CALLBACKS htcCallbacks;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n"));
if (HTCInitialized) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
return A_OK;
}
A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO));
A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS));
/* setup HIF layer callbacks */
htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler;
htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler;
/* the device layer handles these */
htcCallbacks.rwCompletionHandler = DevRWCompletionHandler;
htcCallbacks.dsrHandler = DevDsrHandler;
HIFInit(&htcCallbacks);
HTCInitialized = TRUE;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n"));
return A_OK;
}
void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList)
{
LOCK_HTC(target);
HTC_PACKET_ENQUEUE(pList,pPacket);
UNLOCK_HTC(target);
}
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList)
{
HTC_PACKET *pPacket;
LOCK_HTC(target);
pPacket = HTC_PACKET_DEQUEUE(pList);
UNLOCK_HTC(target);
return pPacket;
}
/* cleanup the HTC instance */
static void HTCCleanup(HTC_TARGET *target)
{
if (A_IS_MUTEX_VALID(&target->HTCLock)) {
A_MUTEX_DELETE(&target->HTCLock);
}
if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
A_MUTEX_DELETE(&target->HTCRxLock);
}
if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
A_MUTEX_DELETE(&target->HTCTxLock);
}
/* free our instance */
A_FREE(target);
}
/* registered target arrival callback from the HIF layer */
static A_STATUS HTCTargetInsertedHandler(void *hif_handle)
{
HTC_TARGET *target = NULL;
A_STATUS status;
int i;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n"));
do {
/* allocate target memory */
if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
status = A_ERROR;
break;
}
A_MEMZERO(target, sizeof(HTC_TARGET));
A_MUTEX_INIT(&target->HTCLock);
A_MUTEX_INIT(&target->HTCRxLock);
A_MUTEX_INIT(&target->HTCTxLock);
INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
/* give device layer the hif device handle */
target->Device.HIFDevice = hif_handle;
/* give the device layer our context (for event processing)
* the device layer will register it's own context with HIF
* so we need to set this so we can fetch it in the target remove handler */
target->Device.HTCContext = target;
/* set device layer target failure callback */
target->Device.TargetFailureCallback = HTCReportFailure;
/* set device layer recv message pending callback */
target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
target->EpWaitingForBuffers = ENDPOINT_MAX;
/* setup device layer */
status = DevSetup(&target->Device);
if (A_FAILED(status)) {
break;
}
/* carve up buffers/packets for control messages */
for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
HTC_PACKET *pControlPacket;
pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
target,
target->HTCControlBuffers[i].Buffer,
HTC_CONTROL_BUFFER_SIZE,
ENDPOINT_0);
HTC_FREE_CONTROL_RX(target,pControlPacket);
}
for (;i < NUM_CONTROL_BUFFERS;i++) {
HTC_PACKET *pControlPacket;
pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
INIT_HTC_PACKET_INFO(pControlPacket,
target->HTCControlBuffers[i].Buffer,
HTC_CONTROL_BUFFER_SIZE);
HTC_FREE_CONTROL_TX(target,pControlPacket);
}
} while (FALSE);
if (A_SUCCESS(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n"));
/* announce ourselves */
HTCInitInfo.AddInstance((HTC_HANDLE)target);
} else {
if (target != NULL) {
HTCCleanup(target);
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n"));
return status;
}
/* registered removal callback from the HIF layer */
static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status)
{
HTC_TARGET *target;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle));
if (NULL == handle) {
/* this could be NULL in the event that target initialization failed */
return A_OK;
}
target = ((AR6K_DEVICE *)handle)->HTCContext;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" removing target:0x%X instance:0x%X ... \n",
(A_UINT32)target, (A_UINT32)target->pInstanceContext));
if (target->pInstanceContext != NULL) {
/* let upper layer know, it needs to call HTCStop() */
HTCInitInfo.DeleteInstance(target->pInstanceContext);
}
HIFShutDownDevice(target->Device.HIFDevice);
HTCCleanup(target);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n"));
return A_OK;
}
/* get the low level HIF device for the caller , the caller may wish to do low level
* HIF requests */
void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
return target->Device.HIFDevice;
}
/* set the instance block for this HTC handle, so that on removal, the blob can be
* returned to the caller */
void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
target->pInstanceContext = Instance;
}
/* wait for the target to arrive (sends HTC Ready message)
* this operation is fully synchronous and the message is polled for */
A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
A_STATUS status;
HTC_PACKET *pPacket = NULL;
HTC_READY_MSG *pRdyMsg;
HTC_SERVICE_CONNECT_REQ connect;
HTC_SERVICE_CONNECT_RESP resp;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target));
do {
#ifdef MBOXHW_UNIT_TEST
status = DoMboxHWTest(&target->Device);
if (status != A_OK) {
break;
}
#endif
/* we should be getting 1 control message that the target is ready */
status = HTCWaitforControlMessage(target, &pPacket);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
break;
}
/* we controlled the buffer creation so it has to be properly aligned */
pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer;
if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) ||
(pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
/* this message is not valid */
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) {
/* this message is not valid */
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
target->TargetCredits = pRdyMsg->CreditCount;
target->TargetCreditSize = pRdyMsg->CreditSize;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n",
target->TargetCredits, target->TargetCreditSize));
/* setup our pseudo HTC control endpoint connection */
A_MEMZERO(&connect,sizeof(connect));
A_MEMZERO(&resp,sizeof(resp));
connect.EpCallbacks.pContext = target;
connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
connect.EpCallbacks.EpRecv = HTCControlRecv;
connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */
connect.EpCallbacks.EpSendFull = NULL; /* not needed */
connect.EpCallbacks.EpSendAvail = NULL; /* not needed */
connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
connect.ServiceID = HTC_CTRL_RSVD_SVC;
/* connect fake service */
status = HTCConnectService((HTC_HANDLE)target,
&connect,
&resp);
if (!A_FAILED(status)) {
break;
}
} while (FALSE);
if (pPacket != NULL) {
HTC_FREE_CONTROL_RX(target,pPacket);
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
return status;
}
/* Start HTC, enable interrupts and let the target know host has finished setup */
A_STATUS HTCStart(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_PACKET *pPacket;
A_STATUS status;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
/* now that we are starting, push control receive buffers into the
* HTC control endpoint */
while (1) {
pPacket = HTC_ALLOC_CONTROL_RX(target);
if (NULL == pPacket) {
break;
}
HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
}
do {
AR_DEBUG_ASSERT(target->InitCredits != NULL);
AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
/* call init credits callback to do the distribution ,
* NOTE: the first entry in the distribution list is ENDPOINT_0, so
* we pass the start of the list after this one. */
target->InitCredits(target->pCredDistContext,
target->EpCreditDistributionListHead->pNext,
target->TargetCredits);
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
DumpCreditDistStates(target);
}
/* the caller is done connecting to services, so we can indicate to the
* target that the setup phase is complete */
status = HTCSendSetupComplete(target);
if (A_FAILED(status)) {
break;
}
/* unmask interrupts */
status = DevUnmaskInterrupts(&target->Device);
if (A_FAILED(status)) {
HTCStop(target);
}
} while (FALSE);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
return status;
}
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
void HTCStop(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
/* mark that we are shutting down .. */
target->HTCStateFlags |= HTC_STATE_STOPPING;
/* Masking interrupts is a synchronous operation, when this function returns
* all pending HIF I/O has completed, we can safely flush the queues */
DevMaskInterrupts(&target->Device);
/* flush all send packets */
HTCFlushSendPkts(target);
/* flush all recv buffers */
HTCFlushRecvBuffers(target);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
}
/* undo what was done in HTCInit() */
void HTCShutDown(void)
{
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n"));
HTCInitialized = FALSE;
/* undo HTCInit */
HIFShutDownDevice(NULL);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n"));
}
void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
LOCK_HTC_TX(target);
DumpCreditDistStates(target);
UNLOCK_HTC_TX(target);
}
/* report a target failure from the device, this is a callback from the device layer
* which uses a mechanism to report errors from the target (i.e. special interrupts) */
static void HTCReportFailure(void *Context)
{
HTC_TARGET *target = (HTC_TARGET *)Context;
target->TargetFailure = TRUE;
if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) {
/* let upper layer know, it needs to call HTCStop() */
HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR);
}
}
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
{
A_CHAR stream[60];
A_UINT32 i;
A_UINT16 offset, count;
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription));
count = 0;
offset = 0;
for(i = 0; i < length; i++) {
sprintf(stream + offset, "%2.2X ", buffer[i]);
count ++;
offset += 3;
if(count == 16) {
count = 0;
offset = 0;
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
A_MEMZERO(stream, 60);
}
}
if(offset != 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream));
}
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n"));
}
A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
HTC_ENDPOINT_STAT_ACTION Action,
HTC_ENDPOINT_STATS *pStats)
{
#ifdef HTC_EP_STAT_PROFILING
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
A_BOOL clearStats = FALSE;
A_BOOL sample = FALSE;
switch (Action) {
case HTC_EP_STAT_SAMPLE :
sample = TRUE;
break;
case HTC_EP_STAT_SAMPLE_AND_CLEAR :
sample = TRUE;
clearStats = TRUE;
break;
case HTC_EP_STAT_CLEAR :
clearStats = TRUE;
break;
default:
break;
}
A_ASSERT(Endpoint < ENDPOINT_MAX);
/* lock out TX and RX while we sample and/or clear */
LOCK_HTC_TX(target);
LOCK_HTC_RX(target);
if (sample) {
A_ASSERT(pStats != NULL);
/* return the stats to the caller */
A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
}
if (clearStats) {
/* reset stats */
A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS));
}
UNLOCK_HTC_RX(target);
UNLOCK_HTC_TX(target);
return TRUE;
#else
return FALSE;
#endif
}

View file

@ -0,0 +1,65 @@
#ifndef HTC_DEBUG_H_
#define HTC_DEBUG_H_
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
/* ------- Debug related stuff ------- */
enum {
ATH_DEBUG_SEND = 0x0001,
ATH_DEBUG_RECV = 0x0002,
ATH_DEBUG_SYNC = 0x0004,
ATH_DEBUG_DUMP = 0x0008,
ATH_DEBUG_IRQ = 0x0010,
ATH_DEBUG_TRC = 0x0020,
ATH_DEBUG_WARN = 0x0040,
ATH_DEBUG_ERR = 0x0080,
ATH_DEBUG_ANY = 0xFFFF,
};
#ifdef DEBUG
// TODO FIX usage of A_PRINTF!
#define AR_DEBUG_LVL_CHECK(lvl) (debughtc & (lvl))
#define AR_DEBUG_PRINTBUF(buffer, length, desc) do { \
if (debughtc & ATH_DEBUG_DUMP) { \
DebugDumpBytes(buffer, length,desc); \
} \
} while(0)
#define PRINTX_ARG(arg...) arg
#define AR_DEBUG_PRINTF(flags, args) do { \
if (debughtc & (flags)) { \
A_PRINTF(KERN_ALERT PRINTX_ARG args); \
} \
} while (0)
#define AR_DEBUG_ASSERT(test) do { \
if (!(test)) { \
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,#test)); \
} \
} while(0)
extern int debughtc;
#else
#define AR_DEBUG_PRINTF(flags, args)
#define AR_DEBUG_PRINTBUF(buffer, length, desc)
#define AR_DEBUG_ASSERT(test)
#define AR_DEBUG_LVL_CHECK(lvl) 0
#endif
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription);
#endif /*HTC_DEBUG_H_*/

View file

@ -0,0 +1,168 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _HTC_INTERNAL_H_
#define _HTC_INTERNAL_H_
/* for debugging, uncomment this to capture the last frame header, on frame header
* processing errors, the last frame header is dump for comparison */
//#define HTC_CAPTURE_LAST_FRAME
//#define HTC_EP_STAT_PROFILING
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Header files */
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "htc.h"
#include "htc_api.h"
#include "bmi_msg.h"
#include "hif.h"
#include "ar6k.h"
/* HTC operational parameters */
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
#define HTC_TARGET_DEBUG_INTR_MASK 0x01
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
typedef struct _HTC_ENDPOINT {
HTC_SERVICE_ID ServiceID; /* service ID this endpoint is bound to
non-zero value means this endpoint is in use */
HTC_PACKET_QUEUE TxQueue; /* HTC frame buffer TX queue */
HTC_PACKET_QUEUE RxBuffers; /* HTC frame buffer RX list */
HTC_ENDPOINT_CREDIT_DIST CreditDist; /* credit distribution structure (exposed to driver layer) */
HTC_EP_CALLBACKS EpCallBacks; /* callbacks associated with this endpoint */
int MaxTxQueueDepth; /* max depth of the TX queue before we need to
call driver's full handler */
int CurrentTxQueueDepth; /* current TX queue depth */
int MaxMsgLength; /* max length of endpoint message */
#ifdef HTC_EP_STAT_PROFILING
HTC_ENDPOINT_STATS EndPointStats; /* endpoint statistics */
#endif
} HTC_ENDPOINT;
#ifdef HTC_EP_STAT_PROFILING
#define INC_HTC_EP_STAT(p,stat,count) (p)->EndPointStats.stat += (count);
#else
#define INC_HTC_EP_STAT(p,stat,count)
#endif
#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL
#define NUM_CONTROL_BUFFERS 8
#define NUM_CONTROL_TX_BUFFERS 2
#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH)
typedef struct HTC_CONTROL_BUFFER {
HTC_PACKET HtcPacket;
A_UINT8 Buffer[HTC_CONTROL_BUFFER_SIZE];
} HTC_CONTROL_BUFFER;
/* our HTC target state */
typedef struct _HTC_TARGET {
HTC_ENDPOINT EndPoint[ENDPOINT_MAX];
HTC_CONTROL_BUFFER HTCControlBuffers[NUM_CONTROL_BUFFERS];
HTC_ENDPOINT_CREDIT_DIST *EpCreditDistributionListHead;
HTC_PACKET_QUEUE ControlBufferTXFreeList;
HTC_PACKET_QUEUE ControlBufferRXFreeList;
HTC_CREDIT_DIST_CALLBACK DistributeCredits;
HTC_CREDIT_INIT_CALLBACK InitCredits;
void *pCredDistContext;
int TargetCredits;
int TargetCreditSize;
A_MUTEX_T HTCLock;
A_MUTEX_T HTCRxLock;
A_MUTEX_T HTCTxLock;
AR6K_DEVICE Device; /* AR6K - specific state */
A_UINT32 HTCStateFlags;
HTC_ENDPOINT_ID EpWaitingForBuffers;
A_BOOL TargetFailure;
void *pInstanceContext;
#define HTC_STATE_WAIT_BUFFERS (1 << 0)
#define HTC_STATE_STOPPING (1 << 1)
#ifdef HTC_CAPTURE_LAST_FRAME
HTC_FRAME_HDR LastFrameHdr; /* useful for debugging */
A_UINT8 LastTrailer[256];
A_UINT8 LastTrailerLength;
#endif
} HTC_TARGET;
#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING)
#define LOCK_HTC(t) A_MUTEX_LOCK(&(t)->HTCLock);
#define UNLOCK_HTC(t) A_MUTEX_UNLOCK(&(t)->HTCLock);
#define LOCK_HTC_RX(t) A_MUTEX_LOCK(&(t)->HTCRxLock);
#define UNLOCK_HTC_RX(t) A_MUTEX_UNLOCK(&(t)->HTCRxLock);
#define LOCK_HTC_TX(t) A_MUTEX_LOCK(&(t)->HTCTxLock);
#define UNLOCK_HTC_TX(t) A_MUTEX_UNLOCK(&(t)->HTCTxLock);
#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd))
#define HTC_RECYCLE_RX_PKT(target,p) \
{ \
HTC_PACKET_RESET_RX(pPacket); \
HTCAddReceivePkt((HTC_HANDLE)(target),(p)); \
}
/* internal HTC functions */
void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket);
void HTCControlRecv(void *Context, HTC_PACKET *pPacket);
A_STATUS HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket);
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList);
void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList);
A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 Flags);
A_STATUS HTCIssueRecv(HTC_TARGET *target, HTC_PACKET *pPacket);
void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket);
A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc);
void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
A_STATUS HTCSendSetupComplete(HTC_TARGET *target);
void HTCFlushRecvBuffers(HTC_TARGET *target);
void HTCFlushSendPkts(HTC_TARGET *target);
void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist);
void DumpCreditDistStates(HTC_TARGET *target);
void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription);
static INLINE HTC_PACKET *HTC_ALLOC_CONTROL_TX(HTC_TARGET *target) {
HTC_PACKET *pPacket = HTCAllocControlBuffer(target,&target->ControlBufferTXFreeList);
if (pPacket != NULL) {
/* set payload pointer area with some headroom */
pPacket->pBuffer = pPacket->pBufferStart + HTC_HDR_LENGTH;
}
return pPacket;
}
#define HTC_FREE_CONTROL_TX(t,p) HTCFreeControlBuffer((t),(p),&(t)->ControlBufferTXFreeList)
#define HTC_ALLOC_CONTROL_RX(t) HTCAllocControlBuffer((t),&(t)->ControlBufferRXFreeList)
#define HTC_FREE_CONTROL_RX(t,p) \
{ \
HTC_PACKET_RESET_RX(p); \
HTCFreeControlBuffer((t),(p),&(t)->ControlBufferRXFreeList); \
}
#ifdef __cplusplus
}
#endif
#endif /* _HTC_INTERNAL_H_ */

View file

@ -0,0 +1,703 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "htc_internal.h"
#define HTCIssueRecv(t, p) \
DevRecvPacket(&(t)->Device, \
(p), \
(p)->ActualLength)
#define DO_RCV_COMPLETION(t,p,e) \
{ \
if ((p)->ActualLength > 0) { \
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" completing packet 0x%X (%d bytes) on ep : %d \n", \
(A_UINT32)(p), (p)->ActualLength, (p)->Endpoint)); \
(e)->EpCallBacks.EpRecv((e)->EpCallBacks.pContext, \
(p)); \
} else { \
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" recycling empty packet \n")); \
HTC_RECYCLE_RX_PKT((t), (p)); \
} \
}
#ifdef HTC_EP_STAT_PROFILING
#define HTC_RX_STAT_PROFILE(t,ep,lookAhead) \
{ \
LOCK_HTC_RX((t)); \
INC_HTC_EP_STAT((ep), RxReceived, 1); \
if ((lookAhead) != 0) { \
INC_HTC_EP_STAT((ep), RxLookAheads, 1); \
} \
UNLOCK_HTC_RX((t)); \
}
#else
#define HTC_RX_STAT_PROFILE(t,ep,lookAhead)
#endif
static INLINE A_STATUS HTCProcessTrailer(HTC_TARGET *target,
A_UINT8 *pBuffer,
int Length,
A_UINT32 *pNextLookAhead,
HTC_ENDPOINT_ID FromEndpoint)
{
HTC_RECORD_HDR *pRecord;
A_UINT8 *pRecordBuf;
HTC_LOOKAHEAD_REPORT *pLookAhead;
A_UINT8 *pOrigBuffer;
int origLength;
A_STATUS status;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
}
pOrigBuffer = pBuffer;
origLength = Length;
status = A_OK;
while (Length > 0) {
if (Length < sizeof(HTC_RECORD_HDR)) {
status = A_EPROTO;
break;
}
/* these are byte aligned structs */
pRecord = (HTC_RECORD_HDR *)pBuffer;
Length -= sizeof(HTC_RECORD_HDR);
pBuffer += sizeof(HTC_RECORD_HDR);
if (pRecord->Length > Length) {
/* no room left in buffer for record */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
pRecord->Length, pRecord->RecordID, Length));
status = A_EPROTO;
break;
}
/* start of record follows the header */
pRecordBuf = pBuffer;
switch (pRecord->RecordID) {
case HTC_RECORD_CREDITS:
AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
HTCProcessCreditRpt(target,
(HTC_CREDIT_REPORT *)pRecordBuf,
pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
FromEndpoint);
break;
case HTC_RECORD_LOOKAHEAD:
AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
(pNextLookAhead != NULL)) {
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
(" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
pLookAhead->PreValid,
pLookAhead->PostValid));
/* look ahead bytes are valid, copy them over */
((A_UINT8 *)pNextLookAhead)[0] = pLookAhead->LookAhead[0];
((A_UINT8 *)pNextLookAhead)[1] = pLookAhead->LookAhead[1];
((A_UINT8 *)pNextLookAhead)[2] = pLookAhead->LookAhead[2];
((A_UINT8 *)pNextLookAhead)[3] = pLookAhead->LookAhead[3];
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
DebugDumpBytes((A_UINT8 *)pNextLookAhead,4,"Next Look Ahead");
}
}
break;
default:
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
pRecord->RecordID, pRecord->Length));
break;
}
if (A_FAILED(status)) {
break;
}
/* advance buffer past this record for next time around */
pBuffer += pRecord->Length;
Length -= pRecord->Length;
}
if (A_FAILED(status)) {
DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
return status;
}
/* process a received message (i.e. strip off header, process any trailer data)
* note : locks must be released when this function is called */
static A_STATUS HTCProcessRecvHeader(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT32 *pNextLookAhead)
{
A_UINT8 temp;
A_UINT8 *pBuf;
A_STATUS status = A_OK;
A_UINT16 payloadLen;
A_UINT32 lookAhead;
pBuf = pPacket->pBuffer;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
}
do {
/* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
* retrieve 16 bit fields */
payloadLen = A_GET_UINT16_FIELD(pBuf, HTC_FRAME_HDR, PayloadLen);
((A_UINT8 *)&lookAhead)[0] = pBuf[0];
((A_UINT8 *)&lookAhead)[1] = pBuf[1];
((A_UINT8 *)&lookAhead)[2] = pBuf[2];
((A_UINT8 *)&lookAhead)[3] = pBuf[3];
if (lookAhead != pPacket->HTCReserved) {
/* somehow the lookahead that gave us the full read length did not
* reflect the actual header in the pending message */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCProcessRecvHeader, lookahead mismatch! \n"));
DebugDumpBytes((A_UINT8 *)&pPacket->HTCReserved,4,"Expected Message LookAhead");
DebugDumpBytes(pBuf,sizeof(HTC_FRAME_HDR),"Current Frame Header");
#ifdef HTC_CAPTURE_LAST_FRAME
DebugDumpBytes((A_UINT8 *)&target->LastFrameHdr,sizeof(HTC_FRAME_HDR),"Last Frame Header");
if (target->LastTrailerLength != 0) {
DebugDumpBytes(target->LastTrailer,
target->LastTrailerLength,
"Last trailer");
}
#endif
status = A_EPROTO;
break;
}
/* get flags */
temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, Flags);
if (temp & HTC_FLAGS_RECV_TRAILER) {
/* this packet has a trailer */
/* extract the trailer length in control byte 0 */
temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, ControlBytes[0]);
if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
payloadLen, temp));
status = A_EPROTO;
break;
}
/* process trailer data that follows HDR + application payload */
status = HTCProcessTrailer(target,
(pBuf + HTC_HDR_LENGTH + payloadLen - temp),
temp,
pNextLookAhead,
pPacket->Endpoint);
if (A_FAILED(status)) {
break;
}
#ifdef HTC_CAPTURE_LAST_FRAME
A_MEMCPY(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
target->LastTrailerLength = temp;
#endif
/* trim length by trailer bytes */
pPacket->ActualLength -= temp;
}
#ifdef HTC_CAPTURE_LAST_FRAME
else {
target->LastTrailerLength = 0;
}
#endif
/* if we get to this point, the packet is good */
/* remove header and adjust length */
pPacket->pBuffer += HTC_HDR_LENGTH;
pPacket->ActualLength -= HTC_HDR_LENGTH;
} while (FALSE);
if (A_FAILED(status)) {
/* dump the whole packet */
DebugDumpBytes(pBuf,pPacket->ActualLength,"BAD HTC Recv PKT");
} else {
#ifdef HTC_CAPTURE_LAST_FRAME
A_MEMCPY(&target->LastFrameHdr,pBuf,sizeof(HTC_FRAME_HDR));
#endif
if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
if (pPacket->ActualLength > 0) {
AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
}
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
return status;
}
/* asynchronous completion handler for recv packet fetching, when the device layer
* completes a read request, it will call this completion handler */
void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket)
{
HTC_TARGET *target = (HTC_TARGET *)Context;
HTC_ENDPOINT *pEndpoint;
A_UINT32 nextLookAhead = 0;
A_STATUS status;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (status:%d, ep:%d) \n",
pPacket->Status, pPacket->Endpoint));
AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
pEndpoint = &target->EndPoint[pPacket->Endpoint];
pPacket->Completion = NULL;
/* get completion status */
status = pPacket->Status;
do {
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
pPacket->Status, pPacket->Endpoint));
break;
}
/* process the header for any trailer data */
status = HTCProcessRecvHeader(target,pPacket,&nextLookAhead);
if (A_FAILED(status)) {
break;
}
/* was there a lookahead for the next packet? */
if (nextLookAhead != 0) {
A_STATUS nextStatus;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("HTCRecvCompleteHandler - next look ahead was non-zero : 0x%X \n",
nextLookAhead));
/* we have another packet, get the next packet fetch started (pipelined) before
* we call into the endpoint's callback, this will start another async request */
nextStatus = HTCRecvMessagePendingHandler(target,nextLookAhead,NULL);
if (A_EPROTO == nextStatus) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Next look ahead from recv header was INVALID\n"));
DebugDumpBytes((A_UINT8 *)&nextLookAhead,
4,
"BAD lookahead from lookahead report");
}
} else {
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("HTCRecvCompleteHandler - rechecking for more messages...\n"));
/* if we did not get anything on the look-ahead,
* call device layer to asynchronously re-check for messages. If we can keep the async
* processing going we get better performance. If there is a pending message we will keep processing
* messages asynchronously which should pipeline things nicely */
DevCheckPendingRecvMsgsAsync(&target->Device);
}
HTC_RX_STAT_PROFILE(target,pEndpoint,nextLookAhead);
DO_RCV_COMPLETION(target,pPacket,pEndpoint);
} while (FALSE);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
status));
/* recyle this packet */
HTC_RECYCLE_RX_PKT(target, pPacket);
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
}
/* synchronously wait for a control message from the target,
* This function is used at initialization time ONLY. At init messages
* on ENDPOINT 0 are expected. */
A_STATUS HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket)
{
A_STATUS status;
A_UINT32 lookAhead;
HTC_PACKET *pPacket = NULL;
HTC_FRAME_HDR *pHdr;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
do {
*ppControlPacket = NULL;
/* call the polling function to see if we have a message */
status = DevPollMboxMsgRecv(&target->Device,
&lookAhead,
HTC_TARGET_RESPONSE_TIMEOUT);
if (A_FAILED(status)) {
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
/* check the lookahead */
pHdr = (HTC_FRAME_HDR *)&lookAhead;
if (pHdr->EndpointID != ENDPOINT_0) {
/* unexpected endpoint number, should be zero */
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
if (A_FAILED(status)) {
/* bad message */
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
pPacket = HTC_ALLOC_CONTROL_RX(target);
if (pPacket == NULL) {
AR_DEBUG_ASSERT(FALSE);
status = A_NO_MEMORY;
break;
}
pPacket->HTCReserved = lookAhead;
pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
if (pPacket->ActualLength > pPacket->BufferLength) {
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
/* we want synchronous operation */
pPacket->Completion = NULL;
/* get the message from the device, this will block */
status = HTCIssueRecv(target, pPacket);
if (A_FAILED(status)) {
break;
}
/* process receive header */
status = HTCProcessRecvHeader(target,pPacket,NULL);
pPacket->Status = status;
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
status));
break;
}
/* give the caller this control message packet, they are responsible to free */
*ppControlPacket = pPacket;
} while (FALSE);
if (A_FAILED(status)) {
if (pPacket != NULL) {
/* cleanup buffer on error */
HTC_FREE_CONTROL_RX(target,pPacket);
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
return status;
}
/* callback when device layer or lookahead report parsing detects a pending message */
A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc)
{
HTC_TARGET *target = (HTC_TARGET *)Context;
A_STATUS status = A_OK;
HTC_PACKET *pPacket = NULL;
HTC_FRAME_HDR *pHdr;
HTC_ENDPOINT *pEndpoint;
A_BOOL asyncProc = FALSE;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler LookAhead:0x%X \n",LookAhead));
if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
/* We use async mode to get the packets if the device layer supports it.
* The device layer interfaces with HIF in which HIF may have restrictions on
* how interrupts are processed */
asyncProc = TRUE;
}
if (pAsyncProc != NULL) {
/* indicate to caller how we decided to process this */
*pAsyncProc = asyncProc;
}
while (TRUE) {
pHdr = (HTC_FRAME_HDR *)&LookAhead;
if (pHdr->EndpointID >= ENDPOINT_MAX) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
/* invalid endpoint */
status = A_EPROTO;
break;
}
if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
pHdr->PayloadLen, HTC_MAX_PAYLOAD_LENGTH));
status = A_EPROTO;
break;
}
pEndpoint = &target->EndPoint[pHdr->EndpointID];
if (0 == pEndpoint->ServiceID) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
/* endpoint isn't even connected */
status = A_EPROTO;
break;
}
/* lock RX to get a buffer */
LOCK_HTC_RX(target);
/* get a packet from the endpoint recv queue */
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
if (NULL == pPacket) {
/* check for refill handler */
if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
UNLOCK_HTC_RX(target);
/* call the re-fill handler */
pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
pHdr->EndpointID);
LOCK_HTC_RX(target);
/* check if we have more buffers */
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
/* fall through */
}
}
if (NULL == pPacket) {
/* this is not an error, we simply need to mark that we are waiting for buffers.*/
target->HTCStateFlags |= HTC_STATE_WAIT_BUFFERS;
target->EpWaitingForBuffers = pHdr->EndpointID;
status = A_NO_MEMORY;
}
UNLOCK_HTC_RX(target);
if (A_FAILED(status)) {
/* no buffers */
break;
}
AR_DEBUG_ASSERT(pPacket->Endpoint == pHdr->EndpointID);
/* make sure this message can fit in the endpoint buffer */
if ((pHdr->PayloadLen + HTC_HDR_LENGTH) > pPacket->BufferLength) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Payload Length Error : header reports payload of: %d, endpoint buffer size: %d \n",
pHdr->PayloadLen, pPacket->BufferLength));
status = A_EPROTO;
break;
}
pPacket->HTCReserved = LookAhead; /* set expected look ahead */
/* set the amount of data to fetch */
pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
if (asyncProc) {
/* we use async mode to get the packet if the device layer supports it
* set our callback and context */
pPacket->Completion = HTCRecvCompleteHandler;
pPacket->pContext = target;
} else {
/* fully synchronous */
pPacket->Completion = NULL;
}
/* go fetch the packet */
status = HTCIssueRecv(target, pPacket);
if (A_FAILED(status)) {
break;
}
if (asyncProc) {
/* we did this asynchronously so we can get out of the loop, the asynch processing
* creates a chain of requests to continue processing pending messages in the
* context of callbacks */
break;
}
/* in the sync case, we process the packet, check lookaheads and then repeat */
LookAhead = 0;
status = HTCProcessRecvHeader(target,pPacket,&LookAhead);
if (A_FAILED(status)) {
break;
}
HTC_RX_STAT_PROFILE(target,pEndpoint,LookAhead);
DO_RCV_COMPLETION(target,pPacket,pEndpoint);
pPacket = NULL;
if (0 == LookAhead) {
break;
}
}
if (A_NO_MEMORY == status) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" Endpoint :%d has no buffers, blocking receiver to prevent overrun.. \n",
pHdr->EndpointID));
/* try to stop receive at the device layer */
DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
status = A_OK;
} else if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("Failed to get pending message : LookAhead Value: 0x%X (status = %d) \n",
LookAhead, status));
if (pPacket != NULL) {
/* clean up packet on error */
HTC_RECYCLE_RX_PKT(target, pPacket);
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
return status;
}
/* Makes a buffer available to the HTC module */
A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint;
A_BOOL unblockRecv = FALSE;
A_STATUS status = A_OK;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("+- HTCAddReceivePkt: endPointId: %d, buffer: 0x%X, length: %d\n",
pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->BufferLength));
do {
if (HTC_STOPPING(target)) {
status = A_ECANCELED;
break;
}
AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
pEndpoint = &target->EndPoint[pPacket->Endpoint];
LOCK_HTC_RX(target);
/* store receive packet */
HTC_PACKET_ENQUEUE(&pEndpoint->RxBuffers, pPacket);
/* check if we are blocked waiting for a new buffer */
if (target->HTCStateFlags & HTC_STATE_WAIT_BUFFERS) {
if (target->EpWaitingForBuffers == pPacket->Endpoint) {
AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
target->EpWaitingForBuffers));
target->HTCStateFlags &= ~HTC_STATE_WAIT_BUFFERS;
target->EpWaitingForBuffers = ENDPOINT_MAX;
unblockRecv = TRUE;
}
}
UNLOCK_HTC_RX(target);
if (unblockRecv && !HTC_STOPPING(target)) {
/* TODO : implement a buffer threshold count? */
DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
}
} while (FALSE);
return status;
}
static void HTCFlushEndpointRX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
{
HTC_PACKET *pPacket;
LOCK_HTC_RX(target);
while (1) {
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
if (NULL == pPacket) {
break;
}
UNLOCK_HTC_RX(target);
pPacket->Status = A_ECANCELED;
pPacket->ActualLength = 0;
AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%X, length:%d, ep:%d \n",
(A_UINT32)pPacket, pPacket->BufferLength, pPacket->Endpoint));
/* give the packet back */
pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext,
pPacket);
LOCK_HTC_RX(target);
}
UNLOCK_HTC_RX(target);
}
void HTCFlushRecvBuffers(HTC_TARGET *target)
{
HTC_ENDPOINT *pEndpoint;
int i;
/* NOTE: no need to flush endpoint 0, these buffers were
* allocated as part of the HTC struct */
for (i = ENDPOINT_1; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->EndPoint[i];
if (pEndpoint->ServiceID == 0) {
/* not in use.. */
continue;
}
HTCFlushEndpointRX(target,pEndpoint);
}
}

View file

@ -0,0 +1,538 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "htc_internal.h"
#define DO_EP_TX_COMPLETION(ep,p) \
{ \
(p)->Completion = NULL; \
(ep)->EpCallBacks.EpTxComplete((ep)->EpCallBacks.pContext,(p)); \
}
/* call the distribute credits callback with the distribution */
#define DO_DISTRIBUTION(t,reason,description,pList) \
{ \
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
(" calling distribute function (%s) (dfn:0x%X, ctxt:0x%X, dist:0x%X) \n", \
(description), \
(A_UINT32)(t)->DistributeCredits, \
(A_UINT32)(t)->pCredDistContext, \
(A_UINT32)pList)); \
(t)->DistributeCredits((t)->pCredDistContext, \
(pList), \
(reason)); \
}
/* our internal send packet completion handler when packets are submited to the AR6K device
* layer */
static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
{
HTC_TARGET *target = (HTC_TARGET *)Context;
HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint];
if (A_FAILED(pPacket->Status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCSendPktCompletionHandler: request failed (status:%d, ep:%d) \n",
pPacket->Status, pPacket->Endpoint));
}
/* first, fixup the head room we allocated */
pPacket->pBuffer += HTC_HDR_LENGTH;
/* do completion */
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
}
A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 SendFlags)
{
A_STATUS status;
A_UINT8 *pHdrBuf;
A_BOOL sync = FALSE;
/* caller always provides headrooom */
pPacket->pBuffer -= HTC_HDR_LENGTH;
pHdrBuf = pPacket->pBuffer;
/* setup frame header */
A_SET_UINT16_FIELD(pHdrBuf,HTC_FRAME_HDR,PayloadLen,(A_UINT16)pPacket->ActualLength);
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,Flags,SendFlags);
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,EndpointID, (A_UINT8)pPacket->Endpoint);
if (pPacket->Completion == NULL) {
/* mark that this request was synchronously issued */
sync = TRUE;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("+-HTCIssueSend: transmit length : %d (%s) \n",
pPacket->ActualLength + HTC_HDR_LENGTH,
sync ? "SYNC" : "ASYNC" ));
/* send message to device */
status = DevSendPacket(&target->Device,
pPacket,
pPacket->ActualLength + HTC_HDR_LENGTH);
if (sync) {
/* use local sync variable. If this was issued asynchronously, pPacket is no longer
* safe to access. */
pPacket->pBuffer += HTC_HDR_LENGTH;
}
/* if this request was asynchronous, the packet completion routine will be invoked by
* the device layer when the HIF layer completes the request */
return status;
}
/* try to send the current packet or a packet at the head of the TX queue,
* if there are no credits, the packet remains in the queue. */
static void HTCTrySend(HTC_TARGET *target,
HTC_PACKET *pPacketToSend,
HTC_ENDPOINT_ID ep)
{
HTC_PACKET *pPacket;
HTC_ENDPOINT *pEndpoint;
int creditsRequired;
A_UINT8 sendFlags;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (pPkt:0x%X)\n",(A_UINT32)pPacketToSend));
pEndpoint = &target->EndPoint[ep];
LOCK_HTC_TX(target);
if (pPacketToSend != NULL) {
/* caller supplied us a packet to queue to the tail of the HTC TX queue before
* we check the tx queue */
HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue,pPacketToSend);
pEndpoint->CurrentTxQueueDepth++;
}
/* now drain the TX queue for transmission as long as we have enough
* credits */
while (1) {
if (HTC_QUEUE_EMPTY(&pEndpoint->TxQueue)) {
/* nothing in the queue */
break;
}
sendFlags = 0;
/* get packet at head, but don't remove it */
pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%X , Queue Depth: %d\n",
(A_UINT32)pPacket, pEndpoint->CurrentTxQueueDepth));
/* figure out how many credits this message requires */
creditsRequired = pPacket->ActualLength + HTC_HDR_LENGTH;
creditsRequired += target->TargetCreditSize - 1;
creditsRequired /= target->TargetCreditSize;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n",
creditsRequired, pEndpoint->CreditDist.TxCredits));
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
/* not enough credits */
if (pPacket->Endpoint == ENDPOINT_0) {
/* leave it in the queue */
break;
}
/* invoke the registered distribution function only if this is not
* endpoint 0, we let the driver layer provide more credits if it can.
* We pass the credit distribution list starting at the endpoint in question
* */
/* set how many credits we need */
pEndpoint->CreditDist.TxCreditsSeek =
creditsRequired - pEndpoint->CreditDist.TxCredits;
DO_DISTRIBUTION(target,
HTC_CREDIT_DIST_SEEK_CREDITS,
"Seek Credits",
&pEndpoint->CreditDist);
pEndpoint->CreditDist.TxCreditsSeek = 0;
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
/* still not enough credits to send, leave packet in the queue */
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
(" Not enough credits for ep %d leaving packet in queue..\n",
pPacket->Endpoint));
break;
}
}
pEndpoint->CreditDist.TxCredits -= creditsRequired;
INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
/* check if we need credits */
if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n"));
}
/* now we can fully dequeue */
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
pEndpoint->CurrentTxQueueDepth--;
INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
UNLOCK_HTC_TX(target);
HTCIssueSend(target, pPacket, sendFlags);
LOCK_HTC_TX(target);
/* go back and check for more messages */
}
if (pEndpoint->CurrentTxQueueDepth >= pEndpoint->MaxTxQueueDepth) {
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n",
ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth));
UNLOCK_HTC_TX(target);
/* queue is now full, let caller know */
if (pEndpoint->EpCallBacks.EpSendFull != NULL) {
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n"));
pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, ep);
}
} else {
UNLOCK_HTC_TX(target);
/* queue is now available for new packet, let caller know */
if (pEndpoint->EpCallBacks.EpSendAvail)
pEndpoint->EpCallBacks.EpSendAvail(pEndpoint->EpCallBacks.pContext, ep);
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
}
/* HTC API - HTCSendPkt */
A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint;
HTC_ENDPOINT_ID ep;
A_STATUS status = A_OK;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("+HTCSendPkt: Enter endPointId: %d, buffer: 0x%X, length: %d \n",
pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->ActualLength));
ep = pPacket->Endpoint;
AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
pEndpoint = &target->EndPoint[ep];
do {
if (HTC_STOPPING(target)) {
status = A_ECANCELED;
pPacket->Status = status;
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
break;
}
/* everything sent through this interface is asynchronous */
/* fill in HTC completion routines */
pPacket->Completion = HTCSendPktCompletionHandler;
pPacket->pContext = target;
HTCTrySend(target, pPacket, ep);
} while (FALSE);
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n"));
return status;
}
/* check TX queues to drain because of credit distribution update */
static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target)
{
HTC_ENDPOINT *pEndpoint;
HTC_ENDPOINT_CREDIT_DIST *pDistItem;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
pDistItem = target->EpCreditDistributionListHead;
/* run through the credit distribution list to see
* if there are packets queued
* NOTE: no locks need to be taken since the distribution list
* is not dynamic (cannot be re-ordered) and we are not modifying any state */
while (pDistItem != NULL) {
pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved;
if (pEndpoint->CurrentTxQueueDepth > 0) {
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, pEndpoint->CurrentTxQueueDepth));
/* try to start the stalled queue, this list is ordered by priority.
* Highest priority queue get's processed first, if there are credits available the
* highest priority queue will get a chance to reclaim credits from lower priority
* ones */
HTCTrySend(target, NULL, pDistItem->Endpoint);
}
pDistItem = pDistItem->pNext;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
}
/* process credit reports and call distribution function */
void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
{
int i;
HTC_ENDPOINT *pEndpoint;
int totalCredits = 0;
A_BOOL doDist = FALSE;
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
/* lock out TX while we update credits */
LOCK_HTC_TX(target);
for (i = 0; i < NumEntries; i++, pRpt++) {
if (pRpt->EndpointID >= ENDPOINT_MAX) {
AR_DEBUG_ASSERT(FALSE);
break;
}
pEndpoint = &target->EndPoint[pRpt->EndpointID];
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n",
pRpt->EndpointID, pRpt->Credits));
#ifdef HTC_EP_STAT_PROFILING
INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
if (FromEndpoint == pRpt->EndpointID) {
/* this credit report arrived on the same endpoint indicating it arrived in an RX
* packet */
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
} else if (FromEndpoint == ENDPOINT_0) {
/* this credit arrived on endpoint 0 as a NULL message */
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
} else {
/* arrived on another endpoint */
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
}
#endif
if (ENDPOINT_0 == pRpt->EndpointID) {
/* always give endpoint 0 credits back */
pEndpoint->CreditDist.TxCredits += pRpt->Credits;
} else {
/* for all other endpoints, update credits to distribute, the distribution function
* will handle giving out credits back to the endpoints */
pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
/* flag that we have to do the distribution */
doDist = TRUE;
}
totalCredits += pRpt->Credits;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribute \n", totalCredits));
if (doDist) {
/* this was a credit return based on a completed send operations
* note, this is done with the lock held */
DO_DISTRIBUTION(target,
HTC_CREDIT_DIST_SEND_COMPLETE,
"Send Complete",
target->EpCreditDistributionListHead->pNext);
}
UNLOCK_HTC_TX(target);
if (totalCredits) {
HTCCheckEndpointTxQueues(target);
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
}
/* flush endpoint TX queue */
static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_TX_TAG Tag)
{
HTC_PACKET *pPacket;
HTC_PACKET_QUEUE discardQueue;
/* initialize the discard queue */
INIT_HTC_PACKET_QUEUE(&discardQueue);
LOCK_HTC_TX(target);
/* interate from the front of the TX queue and flush out packets */
ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue, pPacket, HTC_PACKET, ListLink) {
/* check for removal */
if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
/* remove from queue */
HTC_PACKET_REMOVE(pPacket);
/* add it to the discard pile */
HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
pEndpoint->CurrentTxQueueDepth--;
}
} ITERATE_END;
UNLOCK_HTC_TX(target);
/* empty the discard queue */
while (1) {
pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
if (NULL == pPacket) {
break;
}
pPacket->Status = A_ECANCELED;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%X, length:%d, ep:%d tag:0x%X \n",
(A_UINT32)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
}
}
void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist)
{
#ifdef DEBUG
HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *)pEPDist->pHTCReserved;
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X --------------\n",
pEPDist->Endpoint, pEPDist->ServiceID));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%X next:0x%X prev:0x%X\n",
(A_UINT32)pEPDist, (A_UINT32)pEPDist->pNext, (A_UINT32)pEPDist->pPrev));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->DistFlags));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCreditsNorm));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCreditsMin));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCredits));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCreditsAssigned));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCreditsSeek));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCreditSize));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCreditsToDist));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n", pEndpoint->CurrentTxQueueDepth));
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
}
void DumpCreditDistStates(HTC_TARGET *target)
{
HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead;
while (pEPList != NULL) {
DumpCreditDist(pEPList);
pEPList = pEPList->pNext;
}
if (target->DistributeCredits != NULL) {
DO_DISTRIBUTION(target,
HTC_DUMP_CREDIT_STATE,
"Dump State",
NULL);
}
}
/* flush all send packets from all endpoint queues */
void HTCFlushSendPkts(HTC_TARGET *target)
{
HTC_ENDPOINT *pEndpoint;
int i;
DumpCreditDistStates(target);
for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
pEndpoint = &target->EndPoint[i];
if (pEndpoint->ServiceID == 0) {
/* not in use.. */
continue;
}
HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
}
}
/* HTC API to flush an endpoint's TX queue*/
void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
if (pEndpoint->ServiceID == 0) {
AR_DEBUG_ASSERT(FALSE);
/* not in use.. */
return;
}
HTCFlushEndpointTX(target, pEndpoint, Tag);
}
/* HTC API to indicate activity to the credit distribution function */
void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
A_BOOL Active)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
A_BOOL doDist = FALSE;
if (pEndpoint->ServiceID == 0) {
AR_DEBUG_ASSERT(FALSE);
/* not in use.. */
return;
}
LOCK_HTC_TX(target);
if (Active) {
if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
/* mark active now */
pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
doDist = TRUE;
}
} else {
if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
/* mark inactive now */
pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
doDist = TRUE;
}
}
if (doDist) {
/* do distribution again based on activity change
* note, this is done with the lock held */
DO_DISTRIBUTION(target,
HTC_CREDIT_DIST_ACTIVITY_CHANGE,
"Activity Change",
target->EpCreditDistributionListHead->pNext);
}
UNLOCK_HTC_TX(target);
}

View file

@ -0,0 +1,403 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "htc_internal.h"
void HTCControlTxComplete(void *Context, HTC_PACKET *pPacket)
{
/* not implemented
* we do not send control TX frames during normal runtime, only during setup */
AR_DEBUG_ASSERT(FALSE);
}
/* callback when a control message arrives on this endpoint */
void HTCControlRecv(void *Context, HTC_PACKET *pPacket)
{
AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0);
/* the only control messages we are expecting are NULL messages (credit resports), which should
* never get here */
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("HTCControlRecv, got message with length:%d \n",
pPacket->ActualLength + HTC_HDR_LENGTH));
/* dump header and message */
DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH,
pPacket->ActualLength + HTC_HDR_LENGTH,
"Unexpected ENDPOINT 0 Message");
HTC_RECYCLE_RX_PKT((HTC_TARGET*)Context,pPacket);
}
A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
{
HTC_PACKET *pSendPacket = NULL;
A_STATUS status;
HTC_SETUP_COMPLETE_MSG *pSetupComplete;
do {
/* allocate a packet to send to the target */
pSendPacket = HTC_ALLOC_CONTROL_TX(target);
if (NULL == pSendPacket) {
status = A_NO_MEMORY;
break;
}
/* assemble setup complete message */
pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
A_MEMZERO(pSetupComplete,sizeof(HTC_SETUP_COMPLETE_MSG));
pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;
SET_HTC_PACKET_INFO_TX(pSendPacket,
NULL,
(A_UINT8 *)pSetupComplete,
sizeof(HTC_SETUP_COMPLETE_MSG),
ENDPOINT_0,
HTC_SERVICE_TX_PACKET_TAG);
/* we want synchronous operation */
pSendPacket->Completion = NULL;
/* send the message */
status = HTCIssueSend(target,pSendPacket,0);
} while (FALSE);
if (pSendPacket != NULL) {
HTC_FREE_CONTROL_TX(target,pSendPacket);
}
return status;
}
A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
HTC_SERVICE_CONNECT_REQ *pConnectReq,
HTC_SERVICE_CONNECT_RESP *pConnectResp)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
A_STATUS status = A_OK;
HTC_PACKET *pRecvPacket = NULL;
HTC_PACKET *pSendPacket = NULL;
HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
HTC_CONNECT_SERVICE_MSG *pConnectMsg;
HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
HTC_ENDPOINT *pEndpoint;
int maxMsgSize = 0;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
(A_UINT32)target, pConnectReq->ServiceID));
do {
AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
/* special case for pseudo control service */
assignedEndpoint = ENDPOINT_0;
maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
} else {
/* allocate a packet to send to the target */
pSendPacket = HTC_ALLOC_CONTROL_TX(target);
if (NULL == pSendPacket) {
AR_DEBUG_ASSERT(FALSE);
status = A_NO_MEMORY;
break;
}
/* assemble connect service message */
pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer;
AR_DEBUG_ASSERT(pConnectMsg != NULL);
A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG));
pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID;
pConnectMsg->ServiceID = pConnectReq->ServiceID;
pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags;
/* check caller if it wants to transfer meta data */
if ((pConnectReq->pMetaData != NULL) &&
(pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
/* copy meta data into message buffer (after header ) */
A_MEMCPY((A_UINT8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG),
pConnectReq->pMetaData,
pConnectReq->MetaDataLength);
pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength;
}
SET_HTC_PACKET_INFO_TX(pSendPacket,
NULL,
(A_UINT8 *)pConnectMsg,
sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
ENDPOINT_0,
HTC_SERVICE_TX_PACKET_TAG);
/* we want synchronous operation */
pSendPacket->Completion = NULL;
status = HTCIssueSend(target,pSendPacket,0);
if (A_FAILED(status)) {
break;
}
/* wait for response */
status = HTCWaitforControlMessage(target, &pRecvPacket);
if (A_FAILED(status)) {
break;
}
/* we controlled the buffer creation so it has to be properly aligned */
pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;
if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) ||
(pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
/* this message is not valid */
AR_DEBUG_ASSERT(FALSE);
status = A_EPROTO;
break;
}
pConnectResp->ConnectRespCode = pResponseMsg->Status;
/* check response status */
if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
(" Target failed service 0x%X connect request (status:%d)\n",
pResponseMsg->ServiceID, pResponseMsg->Status));
status = A_EPROTO;
break;
}
assignedEndpoint = pResponseMsg->EndpointID;
maxMsgSize = pResponseMsg->MaxMsgSize;
if ((pConnectResp->pMetaData != NULL) &&
(pResponseMsg->ServiceMetaLength > 0) &&
(pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
/* caller supplied a buffer and the target responded with data */
int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength);
/* copy the meta data */
A_MEMCPY(pConnectResp->pMetaData,
((A_UINT8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG),
copyLength);
pConnectResp->ActualLength = copyLength;
}
}
/* the rest of these are parameter checks so set the error status */
status = A_EPROTO;
if (assignedEndpoint >= ENDPOINT_MAX) {
AR_DEBUG_ASSERT(FALSE);
break;
}
if (0 == maxMsgSize) {
AR_DEBUG_ASSERT(FALSE);
break;
}
pEndpoint = &target->EndPoint[assignedEndpoint];
if (pEndpoint->ServiceID != 0) {
/* endpoint already in use! */
AR_DEBUG_ASSERT(FALSE);
break;
}
/* return assigned endpoint to caller */
pConnectResp->Endpoint = assignedEndpoint;
pConnectResp->MaxMsgLength = maxMsgSize;
/* setup the endpoint */
pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
pEndpoint->MaxMsgLength = maxMsgSize;
/* copy all the callbacks */
pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers);
INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
/* set the credit distribution info for this endpoint, this information is
* passed back to the credit distribution callback function */
pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID;
pEndpoint->CreditDist.pHTCReserved = pEndpoint;
pEndpoint->CreditDist.Endpoint = assignedEndpoint;
pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize;
pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize;
if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
}
status = A_OK;
} while (FALSE);
if (pSendPacket != NULL) {
HTC_FREE_CONTROL_TX(target,pSendPacket);
}
if (pRecvPacket != NULL) {
HTC_FREE_CONTROL_RX(target,pRecvPacket);
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));
return status;
}
static void AddToEndpointDistList(HTC_TARGET *target, HTC_ENDPOINT_CREDIT_DIST *pEpDist)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEntry,*pLastEntry;
if (NULL == target->EpCreditDistributionListHead) {
target->EpCreditDistributionListHead = pEpDist;
pEpDist->pNext = NULL;
pEpDist->pPrev = NULL;
return;
}
/* queue to the end of the list, this does not have to be very
* fast since this list is built at startup time */
pCurEntry = target->EpCreditDistributionListHead;
while (pCurEntry) {
pLastEntry = pCurEntry;
pCurEntry = pCurEntry->pNext;
}
pLastEntry->pNext = pEpDist;
pEpDist->pPrev = pLastEntry;
pEpDist->pNext = NULL;
}
/* default credit init callback */
static void HTCDefaultCreditInit(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPList,
int TotalCredits)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
int totalEps = 0;
int creditsPerEndpoint;
pCurEpDist = pEPList;
/* first run through the list and figure out how many endpoints we are dealing with */
while (pCurEpDist != NULL) {
pCurEpDist = pCurEpDist->pNext;
totalEps++;
}
/* even distribution */
creditsPerEndpoint = TotalCredits/totalEps;
pCurEpDist = pEPList;
/* run through the list and set minimum and normal credits and
* provide the endpoint with some credits to start */
while (pCurEpDist != NULL) {
if (creditsPerEndpoint < pCurEpDist->TxCreditsPerMaxMsg) {
/* too many endpoints and not enough credits */
AR_DEBUG_ASSERT(FALSE);
break;
}
/* our minimum is set for at least 1 max message */
pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
/* this value is ignored by our credit alg, since we do
* not dynamically adjust credits, this is the policy of
* the "default" credit distribution, something simple and easy */
pCurEpDist->TxCreditsNorm = 0xFFFF;
/* give the endpoint minimum credits */
pCurEpDist->TxCredits = creditsPerEndpoint;
pCurEpDist->TxCreditsAssigned = creditsPerEndpoint;
pCurEpDist = pCurEpDist->pNext;
}
}
/* default credit distribution callback, NOTE, this callback holds the TX lock */
void HTCDefaultCreditDist(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
HTC_CREDIT_DIST_REASON Reason)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
if (Reason == HTC_CREDIT_DIST_SEND_COMPLETE) {
pCurEpDist = pEPDistList;
/* simple distribution */
while (pCurEpDist != NULL) {
if (pCurEpDist->TxCreditsToDist > 0) {
/* just give the endpoint back the credits */
pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
pCurEpDist->TxCreditsToDist = 0;
}
pCurEpDist = pCurEpDist->pNext;
}
}
/* note we do not need to handle the other reason codes as this is a very
* simple distribution scheme, no need to seek for more credits or handle inactivity */
}
void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
void *pCreditDistContext,
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
HTC_SERVICE_ID ServicePriorityOrder[],
int ListLength)
{
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
int i;
int ep;
if (CreditInitFunc != NULL) {
/* caller has supplied their own distribution functions */
target->InitCredits = CreditInitFunc;
AR_DEBUG_ASSERT(CreditDistFunc != NULL);
target->DistributeCredits = CreditDistFunc;
target->pCredDistContext = pCreditDistContext;
} else {
/* caller wants HTC to do distribution */
/* if caller wants service to handle distributions then
* it must set both of these to NULL! */
AR_DEBUG_ASSERT(CreditDistFunc == NULL);
target->InitCredits = HTCDefaultCreditInit;
target->DistributeCredits = HTCDefaultCreditDist;
target->pCredDistContext = target;
}
/* always add HTC control endpoint first, we only expose the list after the
* first one, this is added for TX queue checking */
AddToEndpointDistList(target, &target->EndPoint[ENDPOINT_0].CreditDist);
/* build the list of credit distribution structures in priority order
* supplied by the caller, these will follow endpoint 0 */
for (i = 0; i < ListLength; i++) {
/* match services with endpoints and add the endpoints to the distribution list
* in FIFO order */
for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
if (target->EndPoint[ep].ServiceID == ServicePriorityOrder[i]) {
/* queue this one to the list */
AddToEndpointDistList(target, &target->EndPoint[ep].CreditDist);
break;
}
}
AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2006 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __AR6000_REGDUMP_H__
#define __AR6000_REGDUMP_H__
#if !defined(__ASSEMBLER__)
/*
* Target CPU state at the time of failure is reflected
* in a register dump, which the Host can fetch through
* the diagnostic window.
*/
struct MIPS_exception_frame_s {
A_UINT32 pc; /* Program Counter */
A_UINT32 at; /* MIPS General Purpose registers */
A_UINT32 v0;
A_UINT32 v1;
A_UINT32 a0;
A_UINT32 a1;
A_UINT32 a2;
A_UINT32 a3;
A_UINT32 t0;
A_UINT32 t1;
A_UINT32 t2;
A_UINT32 t3;
A_UINT32 t4;
A_UINT32 t5;
A_UINT32 t6;
A_UINT32 t7;
A_UINT32 s0;
A_UINT32 s1;
A_UINT32 s2;
A_UINT32 s3;
A_UINT32 s4;
A_UINT32 s5;
A_UINT32 s6;
A_UINT32 s7;
A_UINT32 t8;
A_UINT32 t9;
A_UINT32 k0;
A_UINT32 k1;
A_UINT32 gp;
A_UINT32 sp;
A_UINT32 s8;
A_UINT32 ra;
A_UINT32 cause; /* Selected coprocessor regs */
A_UINT32 status;
};
typedef struct MIPS_exception_frame_s CPU_exception_frame_t;
#endif
/*
* Offsets into MIPS_exception_frame structure, for use in assembler code
* MUST MATCH C STRUCTURE ABOVE
*/
#define RD_pc 0
#define RD_at 1
#define RD_v0 2
#define RD_v1 3
#define RD_a0 4
#define RD_a1 5
#define RD_a2 6
#define RD_a3 7
#define RD_t0 8
#define RD_t1 9
#define RD_t2 10
#define RD_t3 11
#define RD_t4 12
#define RD_t5 13
#define RD_t6 14
#define RD_t7 15
#define RD_s0 16
#define RD_s1 17
#define RD_s2 18
#define RD_s3 19
#define RD_s4 20
#define RD_s5 21
#define RD_s6 22
#define RD_s7 23
#define RD_t8 24
#define RD_t9 25
#define RD_k0 26
#define RD_k1 27
#define RD_gp 28
#define RD_sp 29
#define RD_s8 30
#define RD_ra 31
#define RD_cause 32
#define RD_status 33
#define RD_SIZE (34*4) /* Space for this number of words */
#endif /* __AR6000_REGDUMP_H__ */

View file

@ -0,0 +1,36 @@
#define __VER_MAJOR_ 2
#define __VER_MINOR_ 0
#define __VER_PATCH_ 0
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* The makear6ksdk script (used for release builds) modifies the following line.
*/
#define __BUILD_NUMBER_ 18
/* Format of the version number. */
#define VER_MAJOR_BIT_OFFSET 28
#define VER_MINOR_BIT_OFFSET 24
#define VER_PATCH_BIT_OFFSET 16
#define VER_BUILD_NUM_BIT_OFFSET 0
/*
* The version has the following format:
* Bits 28-31: Major version
* Bits 24-27: Minor version
* Bits 16-23: Patch version
* Bits 0-15: Build number (automatically generated during build process )
* E.g. Build 1.1.3.7 would be represented as 0x11030007.
*
* DO NOT split the following macro into multiple lines as this may confuse the build scripts.
*/
#define AR6K_SW_VERSION ( ( __VER_MAJOR_ << VER_MAJOR_BIT_OFFSET ) + ( __VER_MINOR_ << VER_MINOR_BIT_OFFSET ) + ( __VER_PATCH_ << VER_PATCH_BIT_OFFSET ) + ( __BUILD_NUMBER_ << VER_BUILD_NUM_BIT_OFFSET ) )

View file

@ -0,0 +1,36 @@
#define __VER_MAJOR_ 2
#define __VER_MINOR_ 0
#define __VER_PATCH_ 0
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* The makear6ksdk script (used for release builds) modifies the following line.
*/
#define __BUILD_NUMBER_ 18
/* Format of the version number. */
#define VER_MAJOR_BIT_OFFSET 28
#define VER_MINOR_BIT_OFFSET 24
#define VER_PATCH_BIT_OFFSET 16
#define VER_BUILD_NUM_BIT_OFFSET 0
/*
* The version has the following format:
* Bits 28-31: Major version
* Bits 24-27: Minor version
* Bits 16-23: Patch version
* Bits 0-15: Build number (automatically generated during build process )
* E.g. Build 1.1.3.7 would be represented as 0x11030007.
*
* DO NOT split the following macro into multiple lines as this may confuse the build scripts.
*/
#define AR6K_SW_VERSION ( ( __VER_MAJOR_ << VER_MAJOR_BIT_OFFSET ) + ( __VER_MINOR_ << VER_MINOR_BIT_OFFSET ) + ( __VER_PATCH_ << VER_PATCH_BIT_OFFSET ) + ( __BUILD_NUMBER_ << VER_BUILD_NUM_BIT_OFFSET ) )

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This file contains the definitions for AR6001 registers
* that may be directly manipulated by Host software.
*/
#ifndef __AR6KHWREG_H__
#define __AR6KHWREG_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Host registers */
#define HOST_INT_STATUS_ADDRESS 0x00000400
#define CPU_INT_STATUS_ADDRESS 0x00000401
#define ERROR_INT_STATUS_ADDRESS 0x00000402
#define INT_STATUS_ENABLE_ADDRESS 0x00000418
#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
#define COUNT_ADDRESS 0x00000420
#define COUNT_DEC_ADDRESS 0x00000440
#define WINDOW_DATA_ADDRESS 0x00000474
#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
/* Target addresses */
#define RESET_CONTROL_ADDRESS 0x0c000000
#define MC_REMAP_VALID_ADDRESS 0x0c004080
#define MC_REMAP_SIZE_ADDRESS 0x0c004100
#define MC_REMAP_COMPARE_ADDRESS 0x0c004180
#define MC_REMAP_TARGET_ADDRESS 0x0c004200
#define LOCAL_COUNT_ADDRESS 0x0c014080
#define LOCAL_SCRATCH_ADDRESS 0x0c0140c0
#define INT_STATUS_ENABLE_ERROR_MSB 7
#define INT_STATUS_ENABLE_ERROR_LSB 7
#define INT_STATUS_ENABLE_ERROR_MASK 0x00000080
#define INT_STATUS_ENABLE_ERROR_GET(x) (((x) & INT_STATUS_ENABLE_ERROR_MASK) >> INT_STATUS_ENABLE_ERROR_LSB)
#define INT_STATUS_ENABLE_ERROR_SET(x) (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK)
#define INT_STATUS_ENABLE_CPU_MSB 6
#define INT_STATUS_ENABLE_CPU_LSB 6
#define INT_STATUS_ENABLE_CPU_MASK 0x00000040
#define INT_STATUS_ENABLE_CPU_GET(x) (((x) & INT_STATUS_ENABLE_CPU_MASK) >> INT_STATUS_ENABLE_CPU_LSB)
#define INT_STATUS_ENABLE_CPU_SET(x) (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK)
#define INT_STATUS_ENABLE_COUNTER_MSB 4
#define INT_STATUS_ENABLE_COUNTER_LSB 4
#define INT_STATUS_ENABLE_COUNTER_MASK 0x00000010
#define INT_STATUS_ENABLE_COUNTER_GET(x) (((x) & INT_STATUS_ENABLE_COUNTER_MASK) >> INT_STATUS_ENABLE_COUNTER_LSB)
#define INT_STATUS_ENABLE_COUNTER_SET(x) (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & INT_STATUS_ENABLE_COUNTER_MASK)
#define INT_STATUS_ENABLE_MBOX_DATA_MSB 3
#define INT_STATUS_ENABLE_MBOX_DATA_LSB 0
#define INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f
#define INT_STATUS_ENABLE_MBOX_DATA_GET(x) (((x) & INT_STATUS_ENABLE_MBOX_DATA_MASK) >> INT_STATUS_ENABLE_MBOX_DATA_LSB)
#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & INT_STATUS_ENABLE_MBOX_DATA_MASK)
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MSB 1
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) >> ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB)
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK)
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MSB 0
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) >> ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB)
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK)
#define CPU_INT_STATUS_ENABLE_BIT_MSB 7
#define CPU_INT_STATUS_ENABLE_BIT_LSB 0
#define CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
#define CPU_INT_STATUS_ENABLE_BIT_GET(x) (((x) & CPU_INT_STATUS_ENABLE_BIT_MASK) >> CPU_INT_STATUS_ENABLE_BIT_LSB)
#define CPU_INT_STATUS_ENABLE_BIT_SET(x) (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & CPU_INT_STATUS_ENABLE_BIT_MASK)
#define COUNTER_INT_STATUS_ENABLE_BIT_MSB 7
#define COUNTER_INT_STATUS_ENABLE_BIT_LSB 0
#define COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
#define COUNTER_INT_STATUS_ENABLE_BIT_GET(x) (((x) & COUNTER_INT_STATUS_ENABLE_BIT_MASK) >> COUNTER_INT_STATUS_ENABLE_BIT_LSB)
#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & COUNTER_INT_STATUS_ENABLE_BIT_MASK)
#define ERROR_INT_STATUS_WAKEUP_MSB 2
#define ERROR_INT_STATUS_WAKEUP_LSB 2
#define ERROR_INT_STATUS_WAKEUP_MASK 0x00000004
#define ERROR_INT_STATUS_WAKEUP_GET(x) (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> ERROR_INT_STATUS_WAKEUP_LSB)
#define ERROR_INT_STATUS_WAKEUP_SET(x) (((x) << ERROR_INT_STATUS_WAKEUP_LSB) & ERROR_INT_STATUS_WAKEUP_MASK)
#define ERROR_INT_STATUS_RX_UNDERFLOW_MSB 1
#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1
#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002
#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> ERROR_INT_STATUS_RX_UNDERFLOW_LSB)
#define ERROR_INT_STATUS_RX_UNDERFLOW_SET(x) (((x) << ERROR_INT_STATUS_RX_UNDERFLOW_LSB) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK)
#define ERROR_INT_STATUS_TX_OVERFLOW_MSB 0
#define ERROR_INT_STATUS_TX_OVERFLOW_LSB 0
#define ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001
#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> ERROR_INT_STATUS_TX_OVERFLOW_LSB)
#define ERROR_INT_STATUS_TX_OVERFLOW_SET(x) (((x) << ERROR_INT_STATUS_TX_OVERFLOW_LSB) & ERROR_INT_STATUS_TX_OVERFLOW_MASK)
#define HOST_INT_STATUS_ERROR_MSB 7
#define HOST_INT_STATUS_ERROR_LSB 7
#define HOST_INT_STATUS_ERROR_MASK 0x00000080
#define HOST_INT_STATUS_ERROR_GET(x) (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB)
#define HOST_INT_STATUS_ERROR_SET(x) (((x) << HOST_INT_STATUS_ERROR_LSB) & HOST_INT_STATUS_ERROR_MASK)
#define HOST_INT_STATUS_CPU_MSB 6
#define HOST_INT_STATUS_CPU_LSB 6
#define HOST_INT_STATUS_CPU_MASK 0x00000040
#define HOST_INT_STATUS_CPU_GET(x) (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB)
#define HOST_INT_STATUS_CPU_SET(x) (((x) << HOST_INT_STATUS_CPU_LSB) & HOST_INT_STATUS_CPU_MASK)
#define HOST_INT_STATUS_COUNTER_MSB 4
#define HOST_INT_STATUS_COUNTER_LSB 4
#define HOST_INT_STATUS_COUNTER_MASK 0x00000010
#define HOST_INT_STATUS_COUNTER_GET(x) (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB)
#define HOST_INT_STATUS_COUNTER_SET(x) (((x) << HOST_INT_STATUS_COUNTER_LSB) & HOST_INT_STATUS_COUNTER_MASK)
#define RESET_CONTROL_WARM_RST_MSB 7
#define RESET_CONTROL_WARM_RST_LSB 7
#define RESET_CONTROL_WARM_RST_MASK 0x00000080
#define RESET_CONTROL_WARM_RST_GET(x) (((x) & RESET_CONTROL_WARM_RST_MASK) >> RESET_CONTROL_WARM_RST_LSB)
#define RESET_CONTROL_WARM_RST_SET(x) (((x) << RESET_CONTROL_WARM_RST_LSB) & RESET_CONTROL_WARM_RST_MASK)
#define RESET_CONTROL_COLD_RST_MSB 8
#define RESET_CONTROL_COLD_RST_LSB 8
#define RESET_CONTROL_COLD_RST_MASK 0x00000100
#define RESET_CONTROL_COLD_RST_GET(x) (((x) & RESET_CONTROL_COLD_RST_MASK) >> RESET_CONTROL_COLD_RST_LSB)
#define RESET_CONTROL_COLD_RST_SET(x) (((x) << RESET_CONTROL_COLD_RST_LSB) & RESET_CONTROL_COLD_RST_MASK)
#define RESET_CAUSE_LAST_MSB 2
#define RESET_CAUSE_LAST_LSB 0
#define RESET_CAUSE_LAST_MASK 0x00000007
#define RESET_CAUSE_LAST_GET(x) (((x) & RESET_CAUSE_LAST_MASK) >> RESET_CAUSE_LAST_LSB)
#define RESET_CAUSE_LAST_SET(x) (((x) << RESET_CAUSE_LAST_LSB) & RESET_CAUSE_LAST_MASK)
#ifdef __cplusplus
}
#endif
#endif /* __AR6KHWREG_H__ */

View file

@ -0,0 +1,27 @@
#ifndef _A_CONFIG_H_
#define _A_CONFIG_H_
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
/*
* This file contains software configuration options that enables
* specific software "features"
*/
#include "../ar6000/config_linux.h"
#endif

View file

@ -0,0 +1,41 @@
#ifndef _A_DEBUG_H_
#define _A_DEBUG_H_
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include <a_types.h>
#include <a_osapi.h>
#define DBG_INFO 0x00000001
#define DBG_ERROR 0x00000002
#define DBG_WARNING 0x00000004
#define DBG_SDIO 0x00000008
#define DBG_HIF 0x00000010
#define DBG_HTC 0x00000020
#define DBG_WMI 0x00000040
#define DBG_WMI2 0x00000080
#define DBG_DRIVER 0x00000100
#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
#include "../ar6000/debug_linux.h"
#endif

View file

@ -0,0 +1,28 @@
#ifndef _A_DRV_H_
#define _A_DRV_H_
/*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_drv.h#1 $
*
* This file contains the definitions of the basic atheros data types.
* It is used to map the data types in atheros files to a platform specific
* type.
*
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "../ar6000/athdrv_linux.h"
#endif /* _ADRV_H_ */

View file

@ -0,0 +1,185 @@
#ifndef _A_DRV_API_H_
#define _A_DRV_API_H_
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************/
/****************************************************************************/
/** **/
/** WMI related hooks **/
/** **/
/****************************************************************************/
/****************************************************************************/
#include <ar6000_api.h>
#define A_WMI_CHANNELLIST_RX(devt, numChan, chanList) \
ar6000_channelList_rx((devt), (numChan), (chanList))
#define A_WMI_SET_NUMDATAENDPTS(devt, num) \
ar6000_set_numdataendpts((devt), (num))
#define A_WMI_CONTROL_TX(devt, osbuf, streamID) \
ar6000_control_tx((devt), (osbuf), (streamID))
#define A_WMI_TARGETSTATS_EVENT(devt, pStats) \
ar6000_targetStats_event((devt), (pStats))
#define A_WMI_SCANCOMPLETE_EVENT(devt, status) \
ar6000_scanComplete_event((devt), (status))
#ifdef CONFIG_HOST_DSET_SUPPORT
#define A_WMI_DSET_DATA_REQ(devt, access_cookie, offset, length, targ_buf, targ_reply_fn, targ_reply_arg) \
ar6000_dset_data_req((devt), (access_cookie), (offset), (length), (targ_buf), (targ_reply_fn), (targ_reply_arg))
#define A_WMI_DSET_CLOSE(devt, access_cookie) \
ar6000_dset_close((devt), (access_cookie))
#endif
#define A_WMI_DSET_OPEN_REQ(devt, id, targ_handle, targ_reply_fn, targ_reply_arg) \
ar6000_dset_open_req((devt), (id), (targ_handle), (targ_reply_fn), (targ_reply_arg))
#define A_WMI_CONNECT_EVENT(devt, channel, bssid, listenInterval, beaconInterval, networkType, beaconIeLen, assocReqLen, assocRespLen, assocInfo) \
ar6000_connect_event((devt), (channel), (bssid), (listenInterval), (beaconInterval), (networkType), (beaconIeLen), (assocReqLen), (assocRespLen), (assocInfo))
#define A_WMI_REGDOMAIN_EVENT(devt, regCode) \
ar6000_regDomain_event((devt), (regCode))
#define A_WMI_NEIGHBORREPORT_EVENT(devt, numAps, info) \
ar6000_neighborReport_event((devt), (numAps), (info))
#define A_WMI_DISCONNECT_EVENT(devt, reason, bssid, assocRespLen, assocInfo, protocolReasonStatus) \
ar6000_disconnect_event((devt), (reason), (bssid), (assocRespLen), (assocInfo), (protocolReasonStatus))
#define A_WMI_TKIP_MICERR_EVENT(devt, keyid, ismcast) \
ar6000_tkip_micerr_event((devt), (keyid), (ismcast))
#define A_WMI_BITRATE_RX(devt, rateKbps) \
ar6000_bitrate_rx((devt), (rateKbps))
#define A_WMI_TXPWR_RX(devt, txPwr) \
ar6000_txPwr_rx((devt), (txPwr))
#define A_WMI_READY_EVENT(devt, datap, phyCap) \
ar6000_ready_event((devt), (datap), (phyCap))
#define A_WMI_DBGLOG_INIT_DONE(ar) \
ar6000_dbglog_init_done(ar);
#define A_WMI_RSSI_THRESHOLD_EVENT(devt, newThreshold, rssi) \
ar6000_rssiThreshold_event((devt), (newThreshold), (rssi))
#define A_WMI_REPORT_ERROR_EVENT(devt, errorVal) \
ar6000_reportError_event((devt), (errorVal))
#define A_WMI_ROAM_TABLE_EVENT(devt, pTbl) \
ar6000_roam_tbl_event((devt), (pTbl))
#define A_WMI_ROAM_DATA_EVENT(devt, p) \
ar6000_roam_data_event((devt), (p))
#define A_WMI_WOW_LIST_EVENT(devt, num_filters, wow_filters) \
ar6000_wow_list_event((devt), (num_filters), (wow_filters))
#define A_WMI_CAC_EVENT(devt, ac, cac_indication, statusCode, tspecSuggestion) \
ar6000_cac_event((devt), (ac), (cac_indication), (statusCode), (tspecSuggestion))
#define A_WMI_IPTOS_TO_USERPRIORITY(pkt) \
ar6000_iptos_to_userPriority((pkt))
#define A_WMI_PMKID_LIST_EVENT(devt, num_pmkid, pmkid_list) \
ar6000_pmkid_list_event((devt), (num_pmkid), (pmkid_list))
#ifdef CONFIG_HOST_GPIO_SUPPORT
#define A_WMI_GPIO_INTR_RX(intr_mask, input_values) \
ar6000_gpio_intr_rx((intr_mask), (input_values))
#define A_WMI_GPIO_DATA_RX(reg_id, value) \
ar6000_gpio_data_rx((reg_id), (value))
#define A_WMI_GPIO_ACK_RX() \
ar6000_gpio_ack_rx()
#endif
#ifdef SEND_EVENT_TO_APP
#define A_WMI_SEND_EVENT_TO_APP(ar, eventId, datap, len) \
ar6000_send_event_to_app((ar), (eventId), (datap), (len))
#else
#define A_WMI_SEND_EVENT_TO_APP(ar, eventId, datap, len)
#endif
#ifdef CONFIG_HOST_TCMD_SUPPORT
#define A_WMI_TCMD_RX_REPORT_EVENT(devt, results, len) \
ar6000_tcmd_rx_report_event((devt), (results), (len))
#endif
#define A_WMI_HBCHALLENGERESP_EVENT(devt, cookie, source) \
ar6000_hbChallengeResp_event((devt), (cookie), (source))
#define A_WMI_TX_RETRY_ERR_EVENT(devt) \
ar6000_tx_retry_err_event((devt))
#define A_WMI_SNR_THRESHOLD_EVENT_RX(devt, newThreshold, snr) \
ar6000_snrThresholdEvent_rx((devt), (newThreshold), (snr))
#define A_WMI_LQ_THRESHOLD_EVENT_RX(devt, range, lqVal) \
ar6000_lqThresholdEvent_rx((devt), (range), (lqVal))
#define A_WMI_RATEMASK_RX(devt, ratemask) \
ar6000_ratemask_rx((devt), (ratemask))
#define A_WMI_KEEPALIVE_RX(devt, configured) \
ar6000_keepalive_rx((devt), (configured))
#define A_WMI_BSSINFO_EVENT_RX(ar, datp, len) \
ar6000_bssInfo_event_rx((ar), (datap), (len))
#define A_WMI_DBGLOG_EVENT(ar, dropped, buffer, length) \
ar6000_dbglog_event((ar), (dropped), (buffer), (length));
#define A_WMI_STREAM_TX_ACTIVE(devt,trafficClass) \
ar6000_indicate_tx_activity((devt),(trafficClass), TRUE)
#define A_WMI_STREAM_TX_INACTIVE(devt,trafficClass) \
ar6000_indicate_tx_activity((devt),(trafficClass), FALSE)
/****************************************************************************/
/****************************************************************************/
/** **/
/** HTC related hooks **/
/** **/
/****************************************************************************/
/****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,28 @@
#ifndef _A_OSAPI_H_
#define _A_OSAPI_H_
/*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_osapi.h#1 $
*
* This file contains the definitions of the basic atheros data types.
* It is used to map the data types in atheros files to a platform specific
* type.
*
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "../ar6000/osapi_linux.h"
#endif /* _OSAPI_H_ */

View file

@ -0,0 +1,28 @@
#ifndef _A_TYPES_H_
#define _A_TYPES_H_
/*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/a_types.h#1 $
*
* This file contains the definitions of the basic atheros data types.
* It is used to map the data types in atheros files to a platform specific
* type.
*
* Copyright 2003-2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "../ar6000/athtypes_linux.h"
#endif /* _ATHTYPES_H_ */

View file

@ -0,0 +1,29 @@
#ifndef _AR6000_API_H_
#define _AR6000_API_H_
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
* This file contains the API to access the OS dependent atheros host driver
* by the WMI or WLAN generic modules.
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/ar6000_api.h#1 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "../ar6000/ar6xapi_linux.h"
#endif /* _AR6000_API_H */

View file

@ -0,0 +1,38 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef AR6000_DIAG_H_
#define AR6000_DIAG_H_
A_STATUS
ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
A_STATUS
ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
A_STATUS
ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
A_UCHAR *data, A_UINT32 length);
A_STATUS
ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
A_UCHAR *data, A_UINT32 length);
#endif /*AR6000_DIAG_H_*/

View file

@ -0,0 +1,85 @@
#ifndef __ATHDEFS_H__
#define __ATHDEFS_H__
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This file contains definitions that may be used across both
* Host and Target software. Nothing here is module-dependent
* or platform-dependent.
*/
/*
* Generic error codes that can be used by hw, sta, ap, sim, dk
* and any other environments. Since these are enums, feel free to
* add any more codes that you need.
*/
typedef enum {
A_ERROR = -1, /* Generic error return */
A_OK = 0, /* success */
/* Following values start at 1 */
A_DEVICE_NOT_FOUND, /* not able to find PCI device */
A_NO_MEMORY, /* not able to allocate memory, not available */
A_MEMORY_NOT_AVAIL, /* memory region is not free for mapping */
A_NO_FREE_DESC, /* no free descriptors available */
A_BAD_ADDRESS, /* address does not match descriptor */
A_WIN_DRIVER_ERROR, /* used in NT_HW version, if problem at init */
A_REGS_NOT_MAPPED, /* registers not correctly mapped */
A_EPERM, /* Not superuser */
A_EACCES, /* Access denied */
A_ENOENT, /* No such entry, search failed, etc. */
A_EEXIST, /* The object already exists (can't create) */
A_EFAULT, /* Bad address fault */
A_EBUSY, /* Object is busy */
A_EINVAL, /* Invalid parameter */
A_EMSGSIZE, /* Inappropriate message buffer length */
A_ECANCELED, /* Operation canceled */
A_ENOTSUP, /* Operation not supported */
A_ECOMM, /* Communication error on send */
A_EPROTO, /* Protocol error */
A_ENODEV, /* No such device */
A_EDEVNOTUP, /* device is not UP */
A_NO_RESOURCE, /* No resources for requested operation */
A_HARDWARE, /* Hardware failure */
A_PENDING, /* Asynchronous routine; will send up results la
ter (typically in callback) */
A_EBADCHANNEL, /* The channel cannot be used */
A_DECRYPT_ERROR, /* Decryption error */
A_PHY_ERROR, /* RX PHY error */
A_CONSUMED /* Object was consumed */
} A_STATUS;
#define A_SUCCESS(x) (x == A_OK)
#define A_FAILED(x) (!A_SUCCESS(x))
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*
* The following definition is WLAN specific definition
*/
typedef enum {
MODE_11A = 0, /* 11a Mode */
MODE_11G = 1, /* 11g + 11b Mode */
MODE_11B = 2, /* 11b Mode */
MODE_11GONLY = 3, /* 11g only Mode */
MODE_UNKNOWN = 4,
MODE_MAX = 4
} WLAN_PHY_MODE;
typedef enum {
WLAN_11A_CAPABILITY = 1,
WLAN_11G_CAPABILITY = 2,
WLAN_11AG_CAPABILITY = 3,
}WLAN_CAPABILITY;
#endif /* __ATHDEFS_H__ */

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _ATHDRV_H_
#define _ATHDRV_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* _ATHDRV_H_ */

View file

@ -0,0 +1,41 @@
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* @file: athendpack.h
*
* @abstract: end compiler-specific structure packing
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef VXWORKS
#endif /* VXWORKS */
#ifdef LINUX
#endif /* LINUX */
#ifdef QNX
#endif /* QNX */
#ifdef INTEGRITY
#include "integrity/athendpack_integrity.h"
#endif /* INTEGRITY */
#ifdef NUCLEUS
#endif /* NUCLEUS */
#ifdef UNDER_CE
#include "../os/wince/include/athendpack_wince.h"
#endif /* WINCE */

View file

@ -0,0 +1,42 @@
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* @file: athstartpack.h
*
* @abstract: start compiler-specific structure packing
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef VXWORKS
#endif /* VXWORKS */
#ifdef LINUX
#endif /* LINUX */
#ifdef QNX
#endif /* QNX */
#ifdef INTEGRITY
#include "integrity/athstartpack_integrity.h"
#endif /* INTEGRITY */
#ifdef NUCLEUS
#endif /* NUCLEUS */
#ifdef UNDER_CE
#include "../os/wince/include/athstartpack_wince.h"
#endif /* WINCE */

View file

@ -0,0 +1,100 @@
#ifndef _BMI_H_
#define _BMI_H_
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
* BMI declarations and prototypes
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Header files */
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "hif.h"
#include "a_osapi.h"
#include "bmi_msg.h"
void
BMIInit(void);
A_STATUS
BMIDone(HIF_DEVICE *device);
A_STATUS
BMIGetTargetInfo(HIF_DEVICE *device, struct bmi_target_info *targ_info);
A_STATUS
BMIReadMemory(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length);
A_STATUS
BMIWriteMemory(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length);
A_STATUS
BMIExecute(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 *param);
A_STATUS
BMISetAppStart(HIF_DEVICE *device,
A_UINT32 address);
A_STATUS
BMIReadSOCRegister(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 *param);
A_STATUS
BMIWriteSOCRegister(HIF_DEVICE *device,
A_UINT32 address,
A_UINT32 param);
A_STATUS
BMIrompatchInstall(HIF_DEVICE *device,
A_UINT32 ROM_addr,
A_UINT32 RAM_addr,
A_UINT32 nbytes,
A_UINT32 do_activate,
A_UINT32 *patch_id);
A_STATUS
BMIrompatchUninstall(HIF_DEVICE *device,
A_UINT32 rompatch_id);
A_STATUS
BMIrompatchActivate(HIF_DEVICE *device,
A_UINT32 rompatch_count,
A_UINT32 *rompatch_list);
A_STATUS
BMIrompatchDeactivate(HIF_DEVICE *device,
A_UINT32 rompatch_count,
A_UINT32 *rompatch_list);
#ifdef __cplusplus
}
#endif
#endif /* _BMI_H_ */

View file

@ -0,0 +1,199 @@
#ifndef __BMI_MSG_H__
#define __BMI_MSG_H__
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
/*
* Bootloader Messaging Interface (BMI)
*
* BMI is a very simple messaging interface used during initialization
* to read memory, write memory, execute code, and to define an
* application entry PC.
*
* It is used to download an application to AR6K, to provide
* patches to code that is already resident on AR6K, and generally
* to examine and modify state. The Host has an opportunity to use
* BMI only once during bootup. Once the Host issues a BMI_DONE
* command, this opportunity ends.
*
* The Host writes BMI requests to mailbox0, and reads BMI responses
* from mailbox0. BMI requests all begin with a command
* (see below for specific commands), and are followed by
* command-specific data.
*
* Flow control:
* The Host can only issue a command once the Target gives it a
* "BMI Command Credit", using AR6K Counter #4. As soon as the
* Target has completed a command, it issues another BMI Command
* Credit (so the Host can issue the next command).
*
* BMI handles all required Target-side cache flushing.
*/
/* Maximum data size used for BMI transfers */
#define BMI_DATASZ_MAX 32
/* BMI Commands */
#define BMI_NO_COMMAND 0
#define BMI_DONE 1
/*
* Semantics: Host is done using BMI
* Request format:
* A_UINT32 command (BMI_DONE)
* Response format: none
*/
#define BMI_READ_MEMORY 2
/*
* Semantics: Host reads AR6K memory
* Request format:
* A_UINT32 command (BMI_READ_MEMORY)
* A_UINT32 address
* A_UINT32 length, at most BMI_DATASZ_MAX
* Response format:
* A_UINT8 data[length]
*/
#define BMI_WRITE_MEMORY 3
/*
* Semantics: Host writes AR6K memory
* Request format:
* A_UINT32 command (BMI_WRITE_MEMORY)
* A_UINT32 address
* A_UINT32 length, at most BMI_DATASZ_MAX
* A_UINT8 data[length]
* Response format: none
*/
#define BMI_EXECUTE 4
/*
* Semantics: Causes AR6K to execute code
* Request format:
* A_UINT32 command (BMI_EXECUTE)
* A_UINT32 address
* A_UINT32 parameter
* Response format:
* A_UINT32 return value
*/
#define BMI_SET_APP_START 5
/*
* Semantics: Set Target application starting address
* Request format:
* A_UINT32 command (BMI_SET_APP_START)
* A_UINT32 address
* Response format: none
*/
#define BMI_READ_SOC_REGISTER 6
/*
* Semantics: Read a 32-bit Target SOC register.
* Request format:
* A_UINT32 command (BMI_READ_REGISTER)
* A_UINT32 address
* Response format:
* A_UINT32 value
*/
#define BMI_WRITE_SOC_REGISTER 7
/*
* Semantics: Write a 32-bit Target SOC register.
* Request format:
* A_UINT32 command (BMI_WRITE_REGISTER)
* A_UINT32 address
* A_UINT32 value
*
* Response format: none
*/
#define BMI_GET_TARGET_ID 8
#define BMI_GET_TARGET_INFO 8
/*
* Semantics: Fetch the 4-byte Target information
* Request format:
* A_UINT32 command (BMI_GET_TARGET_ID/INFO)
* Response format1 (old firmware):
* A_UINT32 TargetVersionID
* Response format2 (newer firmware):
* A_UINT32 TARGET_VERSION_SENTINAL
* struct bmi_target_info;
*/
struct bmi_target_info {
A_UINT32 target_info_byte_count; /* size of this structure */
A_UINT32 target_ver; /* Target Version ID */
A_UINT32 target_type; /* Target type */
};
#define TARGET_VERSION_SENTINAL 0xffffffff
#define TARGET_TYPE_AR6001 1
#define TARGET_TYPE_AR6002 2
#define BMI_ROMPATCH_INSTALL 9
/*
* Semantics: Install a ROM Patch.
* Request format:
* A_UINT32 command (BMI_ROMPATCH_INSTALL)
* A_UINT32 Target ROM Address
* A_UINT32 Target RAM Address
* A_UINT32 Size, in bytes
* A_UINT32 Activate? 1-->activate;
* 0-->install but do not activate
* Response format:
* A_UINT32 PatchID
*/
#define BMI_ROMPATCH_UNINSTALL 10
/*
* Semantics: Uninstall a previously-installed ROM Patch,
* automatically deactivating, if necessary.
* Request format:
* A_UINT32 command (BMI_ROMPATCH_UNINSTALL)
* A_UINT32 PatchID
*
* Response format: none
*/
#define BMI_ROMPATCH_ACTIVATE 11
/*
* Semantics: Activate a list of previously-installed ROM Patches.
* Request format:
* A_UINT32 command (BMI_ROMPATCH_ACTIVATE)
* A_UINT32 rompatch_count
* A_UINT32 PatchID[rompatch_count]
*
* Response format: none
*/
#define BMI_ROMPATCH_DEACTIVATE 12
/*
* Semantics: Deactivate a list of active ROM Patches.
* Request format:
* A_UINT32 command (BMI_ROMPATCH_DEACTIVATE)
* A_UINT32 rompatch_count
* A_UINT32 PatchID[rompatch_count]
*
* Response format: none
*/
#endif /* __BMI_MSG_H__ */

View file

@ -0,0 +1,61 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef COMMON_DRV_H_
#define COMMON_DRV_H_
#include "hif.h"
#include "htc_packet.h"
/* structure that is the state information for the default credit distribution callback
* drivers should instantiate (zero-init as well) this structure in their driver instance
* and pass it as a context to the HTC credit distribution functions */
typedef struct _COMMON_CREDIT_STATE_INFO {
int TotalAvailableCredits; /* total credits in the system at startup */
int CurrentFreeCredits; /* credits available in the pool that have not been
given out to endpoints */
HTC_ENDPOINT_CREDIT_DIST *pLowestPriEpDist; /* pointer to the lowest priority endpoint dist struct */
} COMMON_CREDIT_STATE_INFO;
/* HTC TX packet tagging definitions */
#define AR6K_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
#define AR6K_DATA_PKT_TAG (AR6K_CONTROL_PKT_TAG + 1)
#ifdef __cplusplus
extern "C" {
#endif
/* OS-independent APIs */
A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo);
A_STATUS ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
A_STATUS ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data);
A_STATUS ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address, A_UCHAR *data, A_UINT32 length);
A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType);
void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType);
A_STATUS ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice);
#ifdef __cplusplus
}
#endif
#endif /*COMMON_DRV_H_*/

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This file contains the definitions and data structures associated with
* the log based debug mechanism.
*
*/
#ifndef _DBGLOG_H_
#define _DBGLOG_H_
#ifdef __cplusplus
extern "C" {
#endif
#define DBGLOG_TIMESTAMP_OFFSET 0
#define DBGLOG_TIMESTAMP_MASK 0x0000FFFF /* Bit 0-15. Contains bit
8-23 of the LF0 timer */
#define DBGLOG_DBGID_OFFSET 16
#define DBGLOG_DBGID_MASK 0x03FF0000 /* Bit 16-25 */
#define DBGLOG_DBGID_NUM_MAX 256 /* Upper limit is width of mask */
#define DBGLOG_MODULEID_OFFSET 26
#define DBGLOG_MODULEID_MASK 0x3C000000 /* Bit 26-29 */
#define DBGLOG_MODULEID_NUM_MAX 16 /* Upper limit is width of mask */
/*
* Please ensure that the definition of any new module intrduced is captured
* between the DBGLOG_MODULEID_START and DBGLOG_MODULEID_END defines. The
* structure is required for the parser to correctly pick up the values for
* different modules.
*/
#define DBGLOG_MODULEID_START
#define DBGLOG_MODULEID_INF 0
#define DBGLOG_MODULEID_WMI 1
#define DBGLOG_MODULEID_CSERV 2
#define DBGLOG_MODULEID_PM 3
#define DBGLOG_MODULEID_TXRX_MGMTBUF 4
#define DBGLOG_MODULEID_TXRX_TXBUF 5
#define DBGLOG_MODULEID_TXRX_RXBUF 6
#define DBGLOG_MODULEID_WOW 7
#define DBGLOG_MODULEID_WHAL 8
#define DBGLOG_MODULEID_END
#define DBGLOG_NUM_ARGS_OFFSET 30
#define DBGLOG_NUM_ARGS_MASK 0xC0000000 /* Bit 30-31 */
#define DBGLOG_NUM_ARGS_MAX 2 /* Upper limit is width of mask */
#define DBGLOG_MODULE_LOG_ENABLE_OFFSET 0
#define DBGLOG_MODULE_LOG_ENABLE_MASK 0x0000FFFF
#define DBGLOG_REPORTING_ENABLED_OFFSET 16
#define DBGLOG_REPORTING_ENABLED_MASK 0x00010000
#define DBGLOG_TIMESTAMP_RESOLUTION_OFFSET 17
#define DBGLOG_TIMESTAMP_RESOLUTION_MASK 0x000E0000
#define DBGLOG_REPORT_SIZE_OFFSET 20
#define DBGLOG_REPORT_SIZE_MASK 0x3FF00000
#define DBGLOG_LOG_BUFFER_SIZE 1500
#define DBGLOG_DBGID_DEFINITION_LEN_MAX 64
struct dbglog_buf_s {
struct dbglog_buf_s *next;
A_INT8 *buffer;
A_UINT32 bufsize;
A_UINT32 length;
A_UINT32 count;
A_UINT32 free;
};
struct dbglog_hdr_s {
struct dbglog_buf_s *dbuf;
A_UINT32 dropped;
};
struct dbglog_config_s {
A_UINT32 cfgvalid; /* Mask with valid config bits */
union {
/* TODO: Take care of endianness */
struct {
A_UINT32 mmask:16; /* Mask of modules with logging on */
A_UINT32 rep:1; /* Reporting enabled or not */
A_UINT32 tsr:3; /* Time stamp resolution. Def: 1 ms */
A_UINT32 size:10; /* Report size in number of messages */
A_UINT32 reserved:2;
} dbglog_config;
A_UINT32 value;
} u;
};
#define cfgmmask u.dbglog_config.mmask
#define cfgrep u.dbglog_config.rep
#define cfgtsr u.dbglog_config.tsr
#define cfgsize u.dbglog_config.size
#define cfgvalue u.value
#ifdef __cplusplus
}
#endif
#endif /* _DBGLOG_H_ */

View file

@ -0,0 +1,46 @@
#ifndef _DBGLOG_API_H_
#define _DBGLOG_API_H_
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
* This file contains host side debug primitives.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "dbglog.h"
#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE
#define DBGLOG_GET_DBGID(arg) \
((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET)
#define DBGLOG_GET_MODULEID(arg) \
((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET)
#define DBGLOG_GET_NUMARGS(arg) \
((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET)
#define DBGLOG_GET_TIMESTAMP(arg) \
((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET)
#ifdef __cplusplus
}
#endif
#endif /* _DBGLOG_API_H_ */

View file

@ -0,0 +1,307 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This file contains the definitions of the debug identifiers for different
* modules.
*
*/
#ifndef _DBGLOG_ID_H_
#define _DBGLOG_ID_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* The nomenclature for the debug identifiers is MODULE_DESCRIPTION.
* Please ensure that the definition of any new debugid introduced is captured
* between the <MODULE>_DBGID_DEFINITION_START and
* <MODULE>_DBGID_DEFINITION_END defines. The structure is required for the
* parser to correctly pick up the values for different debug identifiers.
*/
/* INF debug identifier definitions */
#define INF_DBGID_DEFINITION_START
#define INF_ASSERTION_FAILED 1
#define INF_TARGET_ID 2
#define INF_DBGID_DEFINITION_END
/* WMI debug identifier definitions */
#define WMI_DBGID_DEFINITION_START
#define WMI_CMD_RX_XTND_PKT_TOO_SHORT 1
#define WMI_EXTENDED_CMD_NOT_HANDLED 2
#define WMI_CMD_RX_PKT_TOO_SHORT 3
#define WMI_CALLING_WMI_EXTENSION_FN 4
#define WMI_CMD_NOT_HANDLED 5
#define WMI_IN_SYNC 6
#define WMI_TARGET_WMI_SYNC_CMD 7
#define WMI_SET_SNR_THRESHOLD_PARAMS 8
#define WMI_SET_RSSI_THRESHOLD_PARAMS 9
#define WMI_SET_LQ_TRESHOLD_PARAMS 10
#define WMI_TARGET_CREATE_PSTREAM_CMD 11
#define WMI_WI_DTM_INUSE 12
#define WMI_TARGET_DELETE_PSTREAM_CMD 13
#define WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD 14
#define WMI_TARGET_GET_BIT_RATE_CMD 15
#define WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS 16
#define WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD 17
#define WMI_TARGET_GET_TX_PWR_CMD 18
#define WMI_FREE_EVBUF_WMIBUF 19
#define WMI_FREE_EVBUF_DATABUF 20
#define WMI_FREE_EVBUF_BADFLAG 21
#define WMI_HTC_RX_ERROR_DATA_PACKET 22
#define WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX 23
#define WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT 24
#define WMI_SENDING_READY_EVENT 25
#define WMI_SETPOWER_MDOE_TO_MAXPERF 26
#define WMI_SETPOWER_MDOE_TO_REC 27
#define WMI_BSSINFO_EVENT_FROM 28
#define WMI_TARGET_GET_STATS_CMD 29
#define WMI_SENDING_SCAN_COMPLETE_EVENT 30
#define WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT 31
#define WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT 32
#define WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT 33
#define WMI_SENDING_ERROR_REPORT_EVENT 34
#define WMI_SENDING_CAC_EVENT 35
#define WMI_TARGET_GET_ROAM_TABLE_CMD 36
#define WMI_TARGET_GET_ROAM_DATA_CMD 37
#define WMI_SENDING_GPIO_INTR_EVENT 38
#define WMI_SENDING_GPIO_ACK_EVENT 39
#define WMI_SENDING_GPIO_DATA_EVENT 40
#define WMI_CMD_RX 41
#define WMI_CMD_RX_XTND 42
#define WMI_EVENT_SEND 43
#define WMI_EVENT_SEND_XTND 44
#define WMI_DBGID_DEFINITION_END
/* CSERV debug identifier definitions */
#define CSERV_DBGID_DEFINITION_START
#define CSERV_BEGIN_SCAN1 1
#define CSERV_BEGIN_SCAN2 2
#define CSERV_END_SCAN1 3
#define CSERV_END_SCAN2 4
#define CSERV_CHAN_SCAN_START 5
#define CSERV_CHAN_SCAN_STOP 6
#define CSERV_CHANNEL_OPPPORTUNITY 7
#define CSERV_NC_TIMEOUT 8
#define CSERV_BACK_HOME 10
#define CSERV_CHMGR_CH_CALLBACK1 11
#define CSERV_CHMGR_CH_CALLBACK2 12
#define CSERV_CHMGR_CH_CALLBACK3 13
#define CSERV_SET_SCAN_PARAMS1 14
#define CSERV_SET_SCAN_PARAMS2 15
#define CSERV_SET_SCAN_PARAMS3 16
#define CSERV_SET_SCAN_PARAMS4 17
#define CSERV_ABORT_SCAN 18
#define CSERV_NEWSTATE 19
#define CSERV_MINCHMGR_OP_END 20
#define CSERV_CHMGR_OP_END 21
#define CSERV_DISCONNECT_TIMEOUT 22
#define CSERV_ROAM_TIMEOUT 23
#define CSERV_FORCE_SCAN1 24
#define CSERV_FORCE_SCAN2 25
#define CSERV_FORCE_SCAN3 26
#define CSERV_UTIL_TIMEOUT 27
#define CSERV_RSSIPOLLER 28
#define CSERV_RETRY_CONNECT_TIMEOUT 29
#define CSERV_RSSIINDBMPOLLER 30
#define CSERV_BGSCAN_ENABLE 31
#define CSERV_BGSCAN_DISABLE 32
#define CSERV_WLAN_START_SCAN_CMD1 33
#define CSERV_WLAN_START_SCAN_CMD2 34
#define CSERV_WLAN_START_SCAN_CMD3 35
#define CSERV_START_SCAN_CMD 36
#define CSERV_START_FORCE_SCAN 37
#define CSERV_NEXT_CHAN 38
#define CSERV_SET_REGCODE 39
#define CSERV_START_ADHOC 40
#define CSERV_ADHOC_AT_HOME 41
#define CSERV_OPT_AT_HOME 42
#define CSERV_WLAN_CONNECT_CMD 43
#define CSERV_WLAN_RECONNECT_CMD 44
#define CSERV_WLAN_DISCONNECT_CMD 45
#define CSERV_BSS_CHANGE_CHANNEL 46
#define CSERV_BEACON_RX 47
#define CSERV_KEEPALIVE_CHECK 48
#define CSERV_RC_BEGIN_SCAN 49
#define CSERV_RC_SCAN_START 50
#define CSERV_RC_SCAN_STOP 51
#define CSERV_RC_NEXT 52
#define CSERV_RC_SCAN_END 53
#define CSERV_PROBE_CALLBACK 54
#define CSERV_ROAM1 55
#define CSERV_ROAM2 56
#define CSERV_ROAM3 57
#define CSERV_CONNECT_EVENT 58
#define CSERV_DISCONNECT_EVENT 59
#define CSERV_BMISS_HANDLER1 60
#define CSERV_BMISS_HANDLER2 61
#define CSERV_BMISS_HANDLER3 62
#define CSERV_LOWRSSI_HANDLER 63
#define CSERV_WLAN_SET_PMKID_CMD 64
#define CSERV_RECONNECT_REQUEST 65
#define CSERV_KEYSPLUMBED_EVENT 66
#define CSERV_NEW_REG 67
#define CSERV_SET_RSSI_THOLD 68
#define CSERV_RSSITHRESHOLDCHECK 69
#define CSERV_RSSIINDBMTHRESHOLDCHECK 70
#define CSERV_WLAN_SET_OPT_CMD1 71
#define CSERV_WLAN_SET_OPT_CMD2 72
#define CSERV_WLAN_SET_OPT_CMD3 73
#define CSERV_WLAN_SET_OPT_CMD4 74
#define CSERV_SCAN_CONNECT_STOP 75
#define CSERV_BMISS_HANDLER4 76
#define CSERV_INITIALIZE_TIMER 77
#define CSERV_ARM_TIMER 78
#define CSERV_DISARM_TIMER 79
#define CSERV_UNINITIALIZE_TIMER 80
#define CSERV_DISCONNECT_EVENT2 81
#define CSERV_SCAN_CONNECT_START 82
#define CSERV_BSSINFO_MEMORY_ALLOC_FAILED 83
#define CSERV_SET_SCAN_PARAMS5 84
#define CSERV_DBGID_DEFINITION_END
/* TXRX debug identifier definitions */
#define TXRX_TXBUF_DBGID_DEFINITION_START
#define TXRX_TXBUF_ALLOCATE_BUF 1
#define TXRX_TXBUF_QUEUE_BUF_TO_MBOX 2
#define TXRX_TXBUF_QUEUE_BUF_TO_TXQ 3
#define TXRX_TXBUF_TXQ_DEPTH 4
#define TXRX_TXBUF_IBSS_QUEUE_TO_SFQ 5
#define TXRX_TXBUF_IBSS_QUEUE_TO_TXQ_FRM_SFQ 6
#define TXRX_TXBUF_INITIALIZE_TIMER 7
#define TXRX_TXBUF_ARM_TIMER 8
#define TXRX_TXBUF_DISARM_TIMER 9
#define TXRX_TXBUF_UNINITIALIZE_TIMER 10
#define TXRX_TXBUF_DBGID_DEFINITION_END
#define TXRX_RXBUF_DBGID_DEFINITION_START
#define TXRX_RXBUF_ALLOCATE_BUF 1
#define TXRX_RXBUF_QUEUE_TO_HOST 2
#define TXRX_RXBUF_QUEUE_TO_WLAN 3
#define TXRX_RXBUF_ZERO_LEN_BUF 4
#define TXRX_RXBUF_QUEUE_TO_HOST_LASTBUF_IN_RXCHAIN 5
#define TXRX_RXBUF_LASTBUF_IN_RXCHAIN_ZEROBUF 6
#define TXRX_RXBUF_QUEUE_EMPTY_QUEUE_TO_WLAN 7
#define TXRX_RXBUF_SEND_TO_RECV_MGMT 8
#define TXRX_RXBUF_SEND_TO_IEEE_LAYER 9
#define TXRX_RXBUF_DBGID_DEFINITION_END
#define TXRX_MGMTBUF_DBGID_DEFINITION_START
#define TXRX_MGMTBUF_ALLOCATE_BUF 1
#define TXRX_MGMTBUF_ALLOCATE_SM_BUF 2
#define TXRX_MGMTBUF_ALLOCATE_RMBUF 3
#define TXRX_MGMTBUF_GET_BUF 4
#define TXRX_MGMTBUF_GET_SM_BUF 5
#define TXRX_MGMTBUF_QUEUE_BUF_TO_TXQ 6
#define TXRX_MGMTBUF_REAPED_BUF 7
#define TXRX_MGMTBUF_REAPED_SM_BUF 8
#define TXRX_MGMTBUF_WAIT_FOR_TXQ_DRAIN 9
#define TXRX_MGMTBUF_WAIT_FOR_TXQ_SFQ_DRAIN 10
#define TXRX_MGMTBUF_ENQUEUE_INTO_SFQ 11
#define TXRX_MGMTBUF_DEQUEUE_FROM_SFQ 12
#define TXRX_MGMTBUF_PAUSE_TXQ 13
#define TXRX_MGMTBUF_RESUME_TXQ 14
#define TXRX_MGMTBUF_WAIT_FORTXQ_DRAIN_TIMEOUT 15
#define TXRX_MGMTBUF_DRAINQ 16
#define TXRX_MGMTBUF_INDICATE_Q_DRAINED 17
#define TXRX_MGMTBUF_DBGID_DEFINITION_END
/* PM (Power Module) debug identifier definitions */
#define PM_DBGID_DEFINITION_START
#define PM_INIT 1
#define PM_ENABLE 2
#define PM_SET_STATE 3
#define PM_SET_POWERMODE 4
#define PM_CONN_NOTIFY 5
#define PM_REF_COUNT_NEGATIVE 6
#define PM_APSD_ENABLE 7
#define PM_UPDATE_APSD_STATE 8
#define PM_CHAN_OP_REQ 9
#define PM_SET_MY_BEACON_POLICY 10
#define PM_SET_ALL_BEACON_POLICY 11
#define PM_SET_PM_PARAMS1 12
#define PM_SET_PM_PARAMS2 13
#define PM_ADHOC_SET_PM_CAPS_FAIL 14
#define PM_ADHOC_UNKNOWN_IBSS_ATTRIB_ID 15
#define PM_DBGID_DEFINITION_END
/* Wake on Wireless debug identifier definitions */
#define WOW_DBGID_DEFINITION_START
#define WOW_INIT 1
#define WOW_GET_CONFIG_DSET 2
#define WOW_NO_CONFIG_DSET 3
#define WOW_INVALID_CONFIG_DSET 4
#define WOW_USE_DEFAULT_CONFIG 5
#define WOW_SETUP_GPIO 6
#define WOW_INIT_DONE 7
#define WOW_SET_GPIO_PIN 8
#define WOW_CLEAR_GPIO_PIN 9
#define WOW_SET_WOW_MODE_CMD 10
#define WOW_SET_HOST_MODE_CMD 11
#define WOW_ADD_WOW_PATTERN_CMD 12
#define WOW_NEW_WOW_PATTERN_AT_INDEX 13
#define WOW_DEL_WOW_PATTERN_CMD 14
#define WOW_LIST_CONTAINS_PATTERNS 15
#define WOW_GET_WOW_LIST_CMD 16
#define WOW_INVALID_FILTER_ID 17
#define WOW_INVALID_FILTER_LISTID 18
#define WOW_NO_VALID_FILTER_AT_ID 19
#define WOW_NO_VALID_LIST_AT_ID 20
#define WOW_NUM_PATTERNS_EXCEEDED 21
#define WOW_NUM_LISTS_EXCEEDED 22
#define WOW_GET_WOW_STATS 23
#define WOW_CLEAR_WOW_STATS 24
#define WOW_WAKEUP_HOST 25
#define WOW_EVENT_WAKEUP_HOST 26
#define WOW_EVENT_DISCARD 27
#define WOW_PATTERN_MATCH 28
#define WOW_PATTERN_NOT_MATCH 29
#define WOW_PATTERN_NOT_MATCH_OFFSET 30
#define WOW_DISABLED_HOST_ASLEEP 31
#define WOW_ENABLED_HOST_ASLEEP_NO_PATTERNS 32
#define WOW_ENABLED_HOST_ASLEEP_NO_MATCH_FOUND 33
#define WOW_DBGID_DEFINITION_END
/* WHAL debug identifier definitions */
#define WHAL_DBGID_DEFINITION_START
#define WHAL_ERROR_ANI_CONTROL 1
#define WHAL_ERROR_CHIP_TEST1 2
#define WHAL_ERROR_CHIP_TEST2 3
#define WHAL_ERROR_EEPROM_CHECKSUM 4
#define WHAL_ERROR_EEPROM_MACADDR 5
#define WHAL_ERROR_INTERRUPT_HIU 6
#define WHAL_ERROR_KEYCACHE_RESET 7
#define WHAL_ERROR_KEYCACHE_SET 8
#define WHAL_ERROR_KEYCACHE_TYPE 9
#define WHAL_ERROR_KEYCACHE_TKIPENTRY 10
#define WHAL_ERROR_KEYCACHE_WEPLENGTH 11
#define WHAL_ERROR_PHY_INVALID_CHANNEL 12
#define WHAL_ERROR_POWER_AWAKE 13
#define WHAL_ERROR_POWER_SET 14
#define WHAL_ERROR_RECV_STOPDMA 15
#define WHAL_ERROR_RECV_STOPPCU 16
#define WHAL_ERROR_RESET_CHANNF1 17
#define WHAL_ERROR_RESET_CHANNF2 18
#define WHAL_ERROR_RESET_PM 19
#define WHAL_ERROR_RESET_OFFSETCAL 20
#define WHAL_ERROR_RESET_RFGRANT 21
#define WHAL_ERROR_RESET_RXFRAME 22
#define WHAL_ERROR_RESET_STOPDMA 23
#define WHAL_ERROR_RESET_RECOVER 24
#define WHAL_ERROR_XMIT_COMPUTE 25
#define WHAL_ERROR_XMIT_NOQUEUE 26
#define WHAL_ERROR_XMIT_ACTIVEQUEUE 27
#define WHAL_ERROR_XMIT_BADTYPE 28
#define WHAL_DBGID_DEFINITION_END
#ifdef __cplusplus
}
#endif
#endif /* _DBGLOG_ID_H_ */

View file

@ -0,0 +1,114 @@
/*
*
* Double-link list definitions (adapted from Atheros SDIO stack)
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef __DL_LIST_H___
#define __DL_LIST_H___
#define A_CONTAINING_STRUCT(address, struct_type, field_name)\
((struct_type *)((A_UINT32)(address) - (A_UINT32)(&((struct_type *)0)->field_name)))
/* list functions */
/* pointers for the list */
typedef struct _DL_LIST {
struct _DL_LIST *pPrev;
struct _DL_LIST *pNext;
}DL_LIST, *PDL_LIST;
/*
* DL_LIST_INIT , initialize doubly linked list
*/
#define DL_LIST_INIT(pList)\
{(pList)->pPrev = pList; (pList)->pNext = pList;}
#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList)))
#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext
#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev
/*
* ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member
* NOT: do not use this function if the items in the list are deleted inside the
* iteration loop
*/
#define ITERATE_OVER_LIST(pStart, pTemp) \
for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext)
/* safe iterate macro that allows the item to be removed from the list
* the iteration continues to the next item in the list
*/
#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \
{ \
PDL_LIST pTemp; \
pTemp = (pStart)->pNext; \
while (pTemp != (pStart)) { \
(pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \
pTemp = pTemp->pNext; \
#define ITERATE_END }}
/*
* DL_ListInsertTail - insert pAdd to the end of the list
*/
static INLINE PDL_LIST DL_ListInsertTail(PDL_LIST pList, PDL_LIST pAdd) {
/* insert at tail */
pAdd->pPrev = pList->pPrev;
pAdd->pNext = pList;
pList->pPrev->pNext = pAdd;
pList->pPrev = pAdd;
return pAdd;
}
/*
* DL_ListInsertHead - insert pAdd into the head of the list
*/
static INLINE PDL_LIST DL_ListInsertHead(PDL_LIST pList, PDL_LIST pAdd) {
/* insert at head */
pAdd->pPrev = pList;
pAdd->pNext = pList->pNext;
pList->pNext->pPrev = pAdd;
pList->pNext = pAdd;
return pAdd;
}
#define DL_ListAdd(pList,pItem) DL_ListInsertHead((pList),(pItem))
/*
* DL_ListRemove - remove pDel from list
*/
static INLINE PDL_LIST DL_ListRemove(PDL_LIST pDel) {
pDel->pNext->pPrev = pDel->pPrev;
pDel->pPrev->pNext = pDel->pNext;
/* point back to itself just to be safe, incase remove is called again */
pDel->pNext = pDel;
pDel->pPrev = pDel;
return pDel;
}
/*
* DL_ListRemoveItemFromHead - get a list item from the head
*/
static INLINE PDL_LIST DL_ListRemoveItemFromHead(PDL_LIST pList) {
PDL_LIST pItem = NULL;
if (pList->pNext != pList) {
pItem = pList->pNext;
/* remove the first item from head */
DL_ListRemove(pItem);
}
return pItem;
}
#endif /* __DL_LIST_H___ */

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/dset_api.h#1 $
*
* Host-side DataSet API.
*
*/
#ifndef _DSET_API_H_
#define _DSET_API_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Host-side DataSet support is optional, and is not
* currently required for correct operation. To disable
* Host-side DataSet support, set this to 0.
*/
#ifndef CONFIG_HOST_DSET_SUPPORT
#define CONFIG_HOST_DSET_SUPPORT 1
#endif
/* Called to send a DataSet Open Reply back to the Target. */
A_STATUS wmi_dset_open_reply(struct wmi_t *wmip,
A_UINT32 status,
A_UINT32 access_cookie,
A_UINT32 size,
A_UINT32 version,
A_UINT32 targ_handle,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg);
/* Called to send a DataSet Data Reply back to the Target. */
A_STATUS wmi_dset_data_reply(struct wmi_t *wmip,
A_UINT32 status,
A_UINT8 *host_buf,
A_UINT32 length,
A_UINT32 targ_buf,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _DSET_API_H_ */

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __DSET_INTERNAL_H__
#define __DSET_INTERNAL_H__
/*
* Internal dset definitions, common for DataSet layer.
*/
#define DSET_TYPE_STANDARD 0
#define DSET_TYPE_BPATCHED 1
#define DSET_TYPE_COMPRESSED 2
/* Dataset descriptor */
typedef struct dset_descriptor_s {
struct dset_descriptor_s *next; /* List link. NULL only at the last
descriptor */
A_UINT16 id; /* Dset ID */
A_UINT16 size; /* Dset size. */
void *DataPtr; /* Pointer to raw data for standard
DataSet or pointer to original
dset_descriptor for patched
DataSet */
A_UINT32 data_type; /* DSET_TYPE_*, above */
void *AuxPtr; /* Additional data that might
needed for data_type. For
example, pointer to patch
Dataset descriptor for BPatch. */
} dset_descriptor_t;
#endif /* __DSET_INTERNAL_H__ */

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __DSETID_H__
#define __DSETID_H__
/* Well-known DataSet IDs */
#define DSETID_UNUSED 0x00000000
#define DSETID_BOARD_DATA 0x00000001 /* Cal and board data */
#define DSETID_REGDB 0x00000002 /* Regulatory Database */
#define DSETID_POWER_CONTROL 0x00000003 /* TX Pwr Lim & Ant Gain */
#define DSETID_USER_CONFIG 0x00000004 /* User Configuration */
#define DSETID_ANALOG_CONTROL_DATA_START 0x00000005
#define DSETID_ANALOG_CONTROL_DATA_END 0x00000025
/*
* Get DSETID for various reference clock speeds.
* For each speed there are three DataSets that correspond
* to the three columns of bank6 data (addr, 11a, 11b/g).
* This macro returns the dsetid of the first of those
* three DataSets.
*/
#define ANALOG_CONTROL_DATA_DSETID(refclk) \
(DSETID_ANALOG_CONTROL_DATA_START + 3*refclk)
/*
* There are TWO STARTUP_PATCH DataSets.
* DSETID_STARTUP_PATCH is historical, and was applied before BMI on
* earlier systems. On AR6002, it is applied after BMI, just like
* DSETID_STARTUP_PATCH2.
*/
#define DSETID_STARTUP_PATCH 0x00000026
#define DSETID_GPIO_CONFIG_PATCH 0x00000027
#define DSETID_WLANREGS 0x00000028 /* override wlan regs */
#define DSETID_STARTUP_PATCH2 0x00000029
#define DSETID_WOW_CONFIG 0x00000090 /* WoW Configuration */
/* Add WHAL_INI_DATA_ID to DSETID_INI_DATA for a specific WHAL INI table. */
#define DSETID_INI_DATA 0x00000100
/* Reserved for WHAL INI Tables: 0x100..0x11f */
#define DSETID_INI_DATA_END 0x0000011f
#define DSETID_VENDOR_START 0x00010000 /* Vendor-defined DataSets */
#define DSETID_INDEX_END 0xfffffffe /* Reserved to indicate the
end of a memory-based
DataSet Index */
#define DSETID_INDEX_FREE 0xffffffff /* An unused index entry */
/*
* PATCH DataSet format:
* A list of patches, terminated by a patch with
* address=PATCH_END.
*
* This allows for patches to be stored in flash.
*/
struct patch_s {
A_UINT32 *address;
A_UINT32 data;
};
/*
* Skip some patches. Can be used to erase a single patch in a
* patch DataSet without having to re-write the DataSet. May
* also be used to embed information for use by subsequent
* patch code. The "data" in a PATCH_SKIP tells how many
* bytes of length "patch_s" to skip.
*/
#define PATCH_SKIP ((A_UINT32 *)0x00000000)
/*
* Execute code at the address specified by "data".
* The address of the patch structure is passed as
* the one parameter.
*/
#define PATCH_CODE_ABS ((A_UINT32 *)0x00000001)
/*
* Same as PATCH_CODE_ABS, but treat "data" as an
* offset from the start of the patch word.
*/
#define PATCH_CODE_REL ((A_UINT32 *)0x00000002)
/* Mark the end of this patch DataSet. */
#define PATCH_END ((A_UINT32 *)0xffffffff)
/*
* A DataSet which contains a Binary Patch to some other DataSet
* uses the original dsetid with the DSETID_BPATCH_FLAG bit set.
* Such a BPatch DataSet consists of BPatch metadata followed by
* the bdiff bytes. BPatch metadata consists of a single 32-bit
* word that contains the size of the BPatched final image.
*
* To create a suitable bdiff DataSet, use bdiff in host/tools/bdiff
* to create "diffs":
* bdiff -q -O -nooldmd5 -nonewmd5 -d ORIGfile NEWfile diffs
* Then add BPatch metadata to the start of "diffs".
*
* NB: There are some implementation-induced restrictions
* on which DataSets can be BPatched.
*/
#define DSETID_BPATCH_FLAG 0x80000000
#endif /* __DSETID_H__ */

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2005 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#if defined(AR6001)
#define GPIO_PIN_COUNT 18
#else
#define GPIO_PIN_COUNT 18
#endif
/*
* Possible values for WMIX_GPIO_SET_REGISTER_CMDID.
* NB: These match hardware order, so that addresses can
* easily be computed.
*/
#define GPIO_ID_OUT 0x00000000
#define GPIO_ID_OUT_W1TS 0x00000001
#define GPIO_ID_OUT_W1TC 0x00000002
#define GPIO_ID_ENABLE 0x00000003
#define GPIO_ID_ENABLE_W1TS 0x00000004
#define GPIO_ID_ENABLE_W1TC 0x00000005
#define GPIO_ID_IN 0x00000006
#define GPIO_ID_STATUS 0x00000007
#define GPIO_ID_STATUS_W1TS 0x00000008
#define GPIO_ID_STATUS_W1TC 0x00000009
#define GPIO_ID_PIN0 0x0000000a
#define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n))
#define GPIO_LAST_REGISTER_ID GPIO_ID_PIN(17)
#define GPIO_ID_NONE 0xffffffff

View file

@ -0,0 +1,57 @@
#ifndef _GPIO_API_H_
#define _GPIO_API_H_
/*
* Copyright 2005 Atheros Communications, Inc., All Rights Reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
/*
* Host-side General Purpose I/O API.
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/gpio_api.h#1 $
*/
/*
* Send a command to the Target in order to change output on GPIO pins.
*/
A_STATUS wmi_gpio_output_set(struct wmi_t *wmip,
A_UINT32 set_mask,
A_UINT32 clear_mask,
A_UINT32 enable_mask,
A_UINT32 disable_mask);
/*
* Send a command to the Target requesting input state of GPIO pins.
*/
A_STATUS wmi_gpio_input_get(struct wmi_t *wmip);
/*
* Send a command to the Target to change the value of a GPIO register.
*/
A_STATUS wmi_gpio_register_set(struct wmi_t *wmip,
A_UINT32 gpioreg_id,
A_UINT32 value);
/*
* Send a command to the Target to fetch the value of a GPIO register.
*/
A_STATUS wmi_gpio_register_get(struct wmi_t *wmip, A_UINT32 gpioreg_id);
/*
* Send a command to the Target, acknowledging some GPIO interrupts.
*/
A_STATUS wmi_gpio_intr_ack(struct wmi_t *wmip, A_UINT32 ack_mask);
#endif /* _GPIO_API_H_ */

View file

@ -0,0 +1,296 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
* HIF specific declarations and prototypes
*/
#ifndef _HIF_H_
#define _HIF_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Header files */
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
typedef struct htc_callbacks HTC_CALLBACKS;
typedef struct hif_device HIF_DEVICE;
/*
* direction - Direction of transfer (HIF_READ/HIF_WRITE).
*/
#define HIF_READ 0x00000001
#define HIF_WRITE 0x00000002
#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
/*
* type - An interface may support different kind of read/write commands.
* The command type is divided into a basic and an extended command
* and can be specified using HIF_BASIC_IO/HIF_EXTENDED_IO.
*/
#define HIF_BASIC_IO 0x00000004
#define HIF_EXTENDED_IO 0x00000008
#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO)
/*
* emode - This indicates the whether the command is to be executed in a
* blocking or non-blocking fashion (HIF_SYNCHRONOUS/
* HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
* implemented using the asynchronous mode allowing the the bus
* driver to indicate the completion of operation through the
* registered callback routine. The requirement primarily comes
* from the contexts these operations get called from (a driver's
* transmit context or the ISR context in case of receive).
* Support for both of these modes is essential.
*/
#define HIF_SYNCHRONOUS 0x00000010
#define HIF_ASYNCHRONOUS 0x00000020
#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
/*
* dmode - An interface may support different kinds of commands based on
* the tradeoff between the amount of data it can carry and the
* setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
* HIF_BLOCK_BASIS). In case of latter, the data is rounded off
* to the nearest block size by padding. The size of the block is
* configurable at compile time using the HIF_BLOCK_SIZE and is
* negotiated with the target during initialization after the
* dragon interrupts are enabled.
*/
#define HIF_BYTE_BASIS 0x00000040
#define HIF_BLOCK_BASIS 0x00000080
#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
/*
* amode - This indicates if the address has to be incremented on dragon
* after every read/write operation (HIF?FIXED_ADDRESS/
* HIF_INCREMENTAL_ADDRESS).
*/
#define HIF_FIXED_ADDRESS 0x00000100
#define HIF_INCREMENTAL_ADDRESS 0x00000200
#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_ASYNC_BYTE_FIX \
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_WR_ASYNC_BYTE_INC \
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_ASYNC_BLOCK_INC \
(HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_SYNC_BYTE_FIX \
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_WR_SYNC_BYTE_INC \
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_WR_SYNC_BLOCK_INC \
(HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BYTE_INC \
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BYTE_FIX \
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BYTE_FIX \
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BLOCK_FIX \
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
#define HIF_RD_ASYNC_BYTE_INC \
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_ASYNC_BLOCK_INC \
(HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
#define HIF_RD_SYNC_BLOCK_INC \
(HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
typedef enum {
HIF_DEVICE_POWER_STATE = 0,
HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
HIF_DEVICE_GET_MBOX_ADDR,
HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
HIF_DEVICE_GET_IRQ_PROC_MODE,
HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
} HIF_DEVICE_CONFIG_OPCODE;
/*
* HIF CONFIGURE definitions:
*
* HIF_DEVICE_GET_MBOX_BLOCK_SIZE
* input : none
* output : array of 4 A_UINT32s
* notes: block size is returned for each mailbox (4)
*
* HIF_DEVICE_GET_MBOX_ADDR
* input : none
* output : array of 4 A_UINT32
* notes: address is returned for each mailbox (4) in the array
*
* HIF_DEVICE_GET_PENDING_EVENTS_FUNC
* input : none
* output: HIF_PENDING_EVENTS_FUNC function pointer
* notes: this is optional for the HIF layer, if the request is
* not handled then it indicates that the upper layer can use
* the standard device methods to get pending events (IRQs, mailbox messages etc..)
* otherwise it can call the function pointer to check pending events.
*
* HIF_DEVICE_GET_IRQ_PROC_MODE
* input : none
* output : HIF_DEVICE_IRQ_PROCESSING_MODE (interrupt processing mode)
* note: the hif layer interfaces with the underlying OS-specific bus driver. The HIF
* layer can report whether IRQ processing is requires synchronous behavior or
* can be processed using asynchronous bus requests (typically faster).
*
* HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC
* input :
* output : HIF_MASK_UNMASK_RECV_EVENT function pointer
* notes: this is optional for the HIF layer. The HIF layer may require a special mechanism
* to mask receive message events. The upper layer can call this pointer when it needs
* to mask/unmask receive events (in case it runs out of buffers).
*
*
*/
typedef enum {
HIF_DEVICE_IRQ_SYNC_ONLY, /* for HIF implementations that require the DSR to process all
interrupts before returning */
HIF_DEVICE_IRQ_ASYNC_SYNC, /* for HIF implementations that allow DSR to process interrupts
using ASYNC I/O (that is HIFAckInterrupt can be called at a
later time */
} HIF_DEVICE_IRQ_PROCESSING_MODE;
#define HIF_MAX_DEVICES 1
struct htc_callbacks {
A_UCHAR *name;
A_UINT32 id;
A_STATUS (* deviceInsertedHandler)(void *hif_handle);
A_STATUS (* deviceRemovedHandler)(void *htc_handle, A_STATUS status);
A_STATUS (* deviceSuspendHandler)(void *htc_handle);
A_STATUS (* deviceResumeHandler)(void *htc_handle);
A_STATUS (* deviceWakeupHandler)(void *htc_handle);
A_STATUS (* rwCompletionHandler)(void *context, A_STATUS status);
A_STATUS (* dsrHandler)(void *htc_handle);
};
#define HIF_OTHER_EVENTS (1 << 0) /* other interrupts (non-Recv) are pending, host
needs to read the register table to figure out what */
#define HIF_RECV_MSG_AVAIL (1 << 1) /* pending recv packet */
typedef struct _HIF_PENDING_EVENTS_INFO {
A_UINT32 Events;
A_UINT32 LookAhead;
} HIF_PENDING_EVENTS_INFO;
/* function to get pending events , some HIF modules use special mechanisms
* to detect packet available and other interrupts */
typedef A_STATUS ( *HIF_PENDING_EVENTS_FUNC)(HIF_DEVICE *device,
HIF_PENDING_EVENTS_INFO *pEvents,
void *AsyncContext);
#define HIF_MASK_RECV TRUE
#define HIF_UNMASK_RECV FALSE
/* function to mask recv events */
typedef A_STATUS ( *HIF_MASK_UNMASK_RECV_EVENT)(HIF_DEVICE *device,
A_BOOL Mask,
void *AsyncContext);
/*
* This API is used by the HTC layer to initialize the HIF layer and to
* register different callback routines. Support for following events has
* been captured - DSR, Read/Write completion, Device insertion/removal,
* Device suspension/resumption/wakeup. In addition to this, the API is
* also used to register the name and the revision of the chip. The latter
* can be used to verify the revision of the chip read from the device
* before reporting it to HTC.
*/
int HIFInit(HTC_CALLBACKS *callbacks);
/*
* This API is used to provide the read/write interface over the specific bus
* interface.
* address - Starting address in the dragon's address space. For mailbox
* writes, it refers to the start of the mbox boundary. It should
* be ensured that the last byte falls on the mailbox's EOM. For
* mailbox reads, it refers to the end of the mbox boundary.
* buffer - Pointer to the buffer containg the data to be transmitted or
* received.
* length - Amount of data to be transmitted or received.
* request - Characterizes the attributes of the command.
*/
A_STATUS
HIFReadWrite(HIF_DEVICE *device,
A_UINT32 address,
A_UCHAR *buffer,
A_UINT32 length,
A_UINT32 request,
void *context);
/*
* This can be initiated from the unload driver context ie when the HTCShutdown
* routine is called.
*/
void HIFShutDownDevice(HIF_DEVICE *device);
/*
* This should translate to an acknowledgment to the bus driver indicating that
* the previous interrupt request has been serviced and the all the relevant
* sources have been cleared. HTC is ready to process more interrupts.
* This should prevent the bus driver from raising an interrupt unless the
* previous one has been serviced and acknowledged using the previous API.
*/
void HIFAckInterrupt(HIF_DEVICE *device);
void HIFMaskInterrupt(HIF_DEVICE *device);
void HIFUnMaskInterrupt(HIF_DEVICE *device);
/*
* This set of functions are to be used by the bus driver to notify
* the HIF module about various events.
* These are not implemented if the bus driver provides an alternative
* way for this notification though callbacks for instance.
*/
int HIFInsertEventNotify(void);
int HIFRemoveEventNotify(void);
int HIFIRQEventNotify(void);
int HIFRWCompleteEventNotify(void);
/*
* This function associates a opaque handle with the HIF layer
* to be used in communication with upper layer i.e. HTC.
* This would normaly be a pointer to htc_target data structure.
*/
void HIFSetHandle(void *hif_handle, void *handle);
A_STATUS
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
void *config, A_UINT32 configLen);
struct device;
struct device*
HIFGetOSDevice(HIF_DEVICE *device);
#ifdef __cplusplus
}
#endif
#endif /* _HIF_H_ */

View file

@ -0,0 +1,49 @@
#ifndef _HOST_VERSION_H_
#define _HOST_VERSION_H_
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
* This file contains version information for the sample host driver for the
* AR6000 chip
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/host_version.h#2 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <AR6K_version.h>
/*
* The version number is made up of major, minor, patch and build
* numbers. These are 16 bit numbers. The build and release script will
* set the build number using a Perforce counter. Here the build number is
* set to 9999 so that builds done without the build-release script are easily
* identifiable.
*/
#define ATH_SW_VER_MAJOR __VER_MAJOR_
#define ATH_SW_VER_MINOR __VER_MINOR_
#define ATH_SW_VER_PATCH __VER_PATCH_
#define ATH_SW_VER_BUILD 9999
#ifdef __cplusplus
}
#endif
#endif /* _HOST_VERSION_H_ */

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __HTC_H__
#define __HTC_H__
#ifndef ATH_TARGET
#include "athstartpack.h"
#endif
#define A_OFFSETOF(type,field) (int)(&(((type *)NULL)->field))
#define ASSEMBLE_UNALIGNED_UINT16(p,highbyte,lowbyte) \
(((A_UINT16)(((A_UINT8 *)(p))[(highbyte)])) << 8 | (A_UINT16)(((A_UINT8 *)(p))[(lowbyte)]))
/* alignment independent macros (little-endian) to fetch UINT16s or UINT8s from a
* structure using only the type and field name.
* Use these macros if there is the potential for unaligned buffer accesses. */
#define A_GET_UINT16_FIELD(p,type,field) \
ASSEMBLE_UNALIGNED_UINT16(p,\
A_OFFSETOF(type,field) + 1, \
A_OFFSETOF(type,field))
#define A_SET_UINT16_FIELD(p,type,field,value) \
{ \
((A_UINT8 *)(p))[A_OFFSETOF(type,field)] = (A_UINT8)(value); \
((A_UINT8 *)(p))[A_OFFSETOF(type,field) + 1] = (A_UINT8)((value) >> 8); \
}
#define A_GET_UINT8_FIELD(p,type,field) \
((A_UINT8 *)(p))[A_OFFSETOF(type,field)]
#define A_SET_UINT8_FIELD(p,type,field,value) \
((A_UINT8 *)(p))[A_OFFSETOF(type,field)] = (value)
/****** DANGER DANGER ***************
*
* The frame header length and message formats defined herein were
* selected to accommodate optimal alignment for target processing. This reduces code
* size and improves performance.
*
* Any changes to the header length may alter the alignment and cause exceptions
* on the target. When adding to the message structures insure that fields are
* properly aligned.
*
*/
/* HTC frame header */
typedef PREPACK struct _HTC_FRAME_HDR{
/* do not remove or re-arrange these fields, these are minimally required
* to take advantage of 4-byte lookaheads in some hardware implementations */
A_UINT8 EndpointID;
A_UINT8 Flags;
A_UINT16 PayloadLen; /* length of data (including trailer) that follows the header */
/***** end of 4-byte lookahead ****/
A_UINT8 ControlBytes[2];
/* message payload starts after the header */
} POSTPACK HTC_FRAME_HDR;
/* frame header flags */
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
#define HTC_FLAGS_RECV_TRAILER (1 << 1)
#define HTC_HDR_LENGTH (sizeof(HTC_FRAME_HDR))
#define HTC_MAX_TRAILER_LENGTH 255
#define HTC_MAX_PAYLOAD_LENGTH (2048 - sizeof(HTC_FRAME_HDR))
/* HTC control message IDs */
typedef enum {
HTC_MSG_READY_ID = 1,
HTC_MSG_CONNECT_SERVICE_ID = 2,
HTC_MSG_CONNECT_SERVICE_RESPONSE_ID = 3,
HTC_MSG_SETUP_COMPLETE_ID = 4,
} HTC_MSG_IDS;
#define HTC_MAX_CONTROL_MESSAGE_LENGTH 256
/* base message ID header */
typedef PREPACK struct {
A_UINT16 MessageID;
} POSTPACK HTC_UNKNOWN_MSG;
/* HTC ready message
* direction : target-to-host */
typedef PREPACK struct {
A_UINT16 MessageID; /* ID */
A_UINT16 CreditCount; /* number of credits the target can offer */
A_UINT16 CreditSize; /* size of each credit */
A_UINT8 MaxEndpoints; /* maximum number of endpoints the target has resources for */
A_UINT8 _Pad1;
} POSTPACK HTC_READY_MSG;
#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
/* connect service
* direction : host-to-target */
typedef PREPACK struct {
A_UINT16 MessageID;
A_UINT16 ServiceID; /* service ID of the service to connect to */
A_UINT16 ConnectionFlags; /* connection flags */
#define HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE (1 << 2) /* reduce credit dribbling when
the host needs credits */
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK (0x3)
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH 0x0
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF 0x1
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS 0x2
#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_UNITY 0x3
A_UINT8 ServiceMetaLength; /* length of meta data that follows */
A_UINT8 _Pad1;
/* service-specific meta data starts after the header */
} POSTPACK HTC_CONNECT_SERVICE_MSG;
/* connect response
* direction : target-to-host */
typedef PREPACK struct {
A_UINT16 MessageID;
A_UINT16 ServiceID; /* service ID that the connection request was made */
A_UINT8 Status; /* service connection status */
A_UINT8 EndpointID; /* assigned endpoint ID */
A_UINT16 MaxMsgSize; /* maximum expected message size on this endpoint */
A_UINT8 ServiceMetaLength; /* length of meta data that follows */
A_UINT8 _Pad1;
/* service-specific meta data starts after the header */
} POSTPACK HTC_CONNECT_SERVICE_RESPONSE_MSG;
typedef PREPACK struct {
A_UINT16 MessageID;
/* currently, no other fields */
} POSTPACK HTC_SETUP_COMPLETE_MSG;
/* connect response status codes */
#define HTC_SERVICE_SUCCESS 0 /* success */
#define HTC_SERVICE_NOT_FOUND 1 /* service could not be found */
#define HTC_SERVICE_FAILED 2 /* specific service failed the connect */
#define HTC_SERVICE_NO_RESOURCES 3 /* no resources (i.e. no more endpoints) */
#define HTC_SERVICE_NO_MORE_EP 4 /* specific service is not allowing any more
endpoints */
/* report record IDs */
typedef enum {
HTC_RECORD_NULL = 0,
HTC_RECORD_CREDITS = 1,
HTC_RECORD_LOOKAHEAD = 2,
} HTC_RPT_IDS;
typedef PREPACK struct {
A_UINT8 RecordID; /* Record ID */
A_UINT8 Length; /* Length of record */
} POSTPACK HTC_RECORD_HDR;
typedef PREPACK struct {
A_UINT8 EndpointID; /* Endpoint that owns these credits */
A_UINT8 Credits; /* credits to report since last report */
} POSTPACK HTC_CREDIT_REPORT;
typedef PREPACK struct {
A_UINT8 PreValid; /* pre valid guard */
A_UINT8 LookAhead[4]; /* 4 byte lookahead */
A_UINT8 PostValid; /* post valid guard */
/* NOTE: the LookAhead array is guarded by a PreValid and Post Valid guard bytes.
* The PreValid bytes must equal the inverse of the PostValid byte */
} POSTPACK HTC_LOOKAHEAD_REPORT;
#ifndef ATH_TARGET
#include "athendpack.h"
#endif
#endif /* __HTC_H__ */

View file

@ -0,0 +1,439 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef _HTC_API_H_
#define _HTC_API_H_
#include <htc.h>
#include <htc_services.h>
#include "htc_packet.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* TODO.. for BMI */
#define ENDPOINT1 0
// TODO -remove me, but we have to fix BMI first
#define HTC_MAILBOX_NUM_MAX 4
/* ------ Endpoint IDS ------ */
typedef enum
{
ENDPOINT_UNUSED = -1,
ENDPOINT_0 = 0,
ENDPOINT_1 = 1,
ENDPOINT_2 = 2,
ENDPOINT_3,
ENDPOINT_4,
ENDPOINT_5,
ENDPOINT_6,
ENDPOINT_7,
ENDPOINT_8,
ENDPOINT_MAX,
} HTC_ENDPOINT_ID;
/* this is the amount of header room required by users of HTC */
#define HTC_HEADER_LEN HTC_HDR_LENGTH
typedef void *HTC_HANDLE;
typedef A_UINT16 HTC_SERVICE_ID;
typedef struct _HTC_INIT_INFO {
void (*AddInstance)(HTC_HANDLE);
void (*DeleteInstance)(void *Instance);
void (*TargetFailure)(void *Instance, A_STATUS Status);
} HTC_INIT_INFO;
/* per service connection send completion */
typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *,HTC_PACKET *);
/* per service connection pkt received */
typedef void (*HTC_EP_RECV_PKT)(void *,HTC_PACKET *);
/* Optional per service connection receive buffer re-fill callback,
* On some OSes (like Linux) packets are allocated from a global pool and indicated up
* to the network stack. The driver never gets the packets back from the OS. For these OSes
* a refill callback can be used to allocate and re-queue buffers into HTC.
*
* On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and
* the driver can re-queue these buffers into HTC. In this regard a refill callback is
* unnecessary */
typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint);
/* Optional per service connection callback when a send queue is full. This can occur if the
* host continues queueing up TX packets faster than credits can arrive
* To prevent the host (on some Oses like Linux) from continuously queueing packets
* and consuming resources, this callback is provided so that that the host
* can disable TX in the subsystem (i.e. network stack)
* Other OSes require a "per-packet" indication_RAW_STREAM_NUM_MAX for each completed TX packet, this
* closed loop mechanism will prevent the network stack from overunning the NIC */
typedef void (*HTC_EP_SEND_QUEUE_FULL)(void *, HTC_ENDPOINT_ID Endpoint);
/* Optional per service connection callback when a send queue is available for receive new packet. */
typedef void (*HTC_EP_SEND_QUEUE_AVAIL)(void *, HTC_ENDPOINT_ID Endpoint);
typedef struct _HTC_EP_CALLBACKS {
void *pContext; /* context for each callback */
HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */
HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */
HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */
HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */
HTC_EP_SEND_QUEUE_AVAIL EpSendAvail; /* OPTIONAL send available callback */
} HTC_EP_CALLBACKS;
/* service connection information */
typedef struct _HTC_SERVICE_CONNECT_REQ {
HTC_SERVICE_ID ServiceID; /* service ID to connect to */
A_UINT16 ConnectionFlags; /* connection flags, see htc protocol definition */
A_UINT8 *pMetaData; /* ptr to optional service-specific meta-data */
A_UINT8 MetaDataLength; /* optional meta data length */
HTC_EP_CALLBACKS EpCallbacks; /* endpoint callbacks */
int MaxSendQueueDepth; /* maximum depth of any send queue */
} HTC_SERVICE_CONNECT_REQ;
/* service connection response information */
typedef struct _HTC_SERVICE_CONNECT_RESP {
A_UINT8 *pMetaData; /* caller supplied buffer to optional meta-data */
A_UINT8 BufferLength; /* length of caller supplied buffer */
A_UINT8 ActualLength; /* actual length of meta data */
HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */
int MaxMsgLength; /* max length of all messages over this endpoint */
A_UINT8 ConnectRespCode; /* connect response code from target */
} HTC_SERVICE_CONNECT_RESP;
/* endpoint distribution structure */
typedef struct _HTC_ENDPOINT_CREDIT_DIST {
struct _HTC_ENDPOINT_CREDIT_DIST *pNext;
struct _HTC_ENDPOINT_CREDIT_DIST *pPrev;
HTC_SERVICE_ID ServiceID; /* Service ID (set by HTC) */
HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */
A_UINT32 DistFlags; /* distribution flags, distribution function can
set default activity using SET_EP_ACTIVE() macro */
int TxCreditsNorm; /* credits for normal operation, anything above this
indicates the endpoint is over-subscribed, this field
is only relevant to the credit distribution function */
int TxCreditsMin; /* floor for credit distribution, this field is
only relevant to the credit distribution function */
int TxCreditsAssigned; /* number of credits assigned to this EP, this field
is only relevant to the credit dist function */
int TxCredits; /* current credits available, this field is used by
HTC to determine whether a message can be sent or
must be queued */
int TxCreditsToDist; /* pending credits to distribute on this endpoint, this
is set by HTC when credit reports arrive.
The credit distribution functions sets this to zero
when it distributes the credits */
int TxCreditsSeek; /* this is the number of credits that the current pending TX
packet needs to transmit. This is set by HTC when
and endpoint needs credits in order to transmit */
int TxCreditSize; /* size in bytes of each credit (set by HTC) */
int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */
void *pHTCReserved; /* reserved for HTC use */
} HTC_ENDPOINT_CREDIT_DIST;
#define HTC_EP_ACTIVE (1 << 31)
/* macro to check if an endpoint has gone active, useful for credit
* distributions */
#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE)
#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE
/* credit distibution code that is passed into the distrbution function,
* there are mandatory and optional codes that must be handled */
typedef enum _HTC_CREDIT_DIST_REASON {
HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed
send operations (MANDATORY) resulting in credit reports */
HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */
HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */
HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by
the distribution function */
} HTC_CREDIT_DIST_REASON;
typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPList,
HTC_CREDIT_DIST_REASON Reason);
typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPList,
int TotalCredits);
/* endpoint statistics action */
typedef enum _HTC_ENDPOINT_STAT_ACTION {
HTC_EP_STAT_SAMPLE = 0, /* only read statistics */
HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */
HTC_EP_STAT_CLEAR /* clear only */
} HTC_ENDPOINT_STAT_ACTION;
/* endpoint statistics */
typedef struct _HTC_ENDPOINT_STATS {
A_UINT32 TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on
this endpoint */
A_UINT32 TxIssued; /* running count of TX packets issued */
A_UINT32 TxCreditRpts; /* running count of total credit reports received for this endpoint */
A_UINT32 TxCreditRptsFromRx;
A_UINT32 TxCreditRptsFromOther;
A_UINT32 TxCreditRptsFromEp0;
A_UINT32 TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */
A_UINT32 TxCreditsFromOther; /* count of credits received via another endpoint */
A_UINT32 TxCreditsFromEp0; /* count of credits received via another endpoint */
A_UINT32 TxCreditsConsummed; /* count of consummed credits */
A_UINT32 TxCreditsReturned; /* count of credits returned */
A_UINT32 RxReceived; /* count of RX packets received */
A_UINT32 RxLookAheads; /* count of lookahead records
found in messages received on this endpoint */
} HTC_ENDPOINT_STATS;
/* ------ Function Prototypes ------ */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Initialize HTC
@function name: HTCInit
@input: pInfo - initialization information
@output:
@return: A_OK on success
@notes: The caller initializes global HTC state and registers various instance
notification callbacks (see HTC_INIT_INFO).
@example:
@see also: HTCShutdown
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCInit(HTC_INIT_INFO *pInfo);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Get the underlying HIF device handle
@function name: HTCGetHifDevice
@input: HTCHandle - handle passed into the AddInstance callback
@output:
@return: opaque HIF device handle usable in HIF API calls.
@notes:
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void *HTCGetHifDevice(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Set the associated instance for the HTC handle
@function name: HTCSetInstance
@input: HTCHandle - handle passed into the AddInstance callback
Instance - caller supplied instance object
@output:
@return:
@notes: Caller must set the instance information for the HTC handle in order to receive
notifications for instance deletion (DeleteInstance callback is called) and for target
failure notification.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Set credit distribution parameters
@function name: HTCSetCreditDistribution
@input: HTCHandle - HTC handle
pCreditDistCont - caller supplied context to pass into distribution functions
CreditDistFunc - Distribution function callback
CreditDistInit - Credit Distribution initialization callback
ServicePriorityOrder - Array containing list of service IDs, lowest index is highest
priority
ListLength - number of elements in ServicePriorityOrder
@output:
@return:
@notes: The user can set a custom credit distribution function to handle special requirements
for each endpoint. A default credit distribution routine can be used by setting
CreditInitFunc to NULL. The default credit distribution is only provided for simple
"fair" credit distribution without regard to any prioritization.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
void *pCreditDistContext,
HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
HTC_SERVICE_ID ServicePriorityOrder[],
int ListLength);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Wait for the target to indicate the HTC layer is ready
@function name: HTCWaitTarget
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This API blocks until the target responds with an HTC ready message.
The caller should not connect services until the target has indicated it is
ready.
@example:
@see also: HTCConnectService
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Start target service communications
@function name: HTCStart
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This API indicates to the target that the service connection phase is complete
and the target can freely start all connected services. This API should only be
called AFTER all service connections have been made. TCStart will issue a
SETUP_COMPLETE message to the target to indicate that all service connections
have been made and the target can start communicating over the endpoints.
@example:
@see also: HTCConnectService
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCStart(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Add receive packet to HTC
@function name: HTCAddReceivePkt
@input: HTCHandle - HTC handle
pPacket - HTC receive packet to add
@output:
@return: A_OK on success
@notes: user must supply HTC packets for capturing incomming HTC frames. The caller
must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
macro.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Connect to an HTC service
@function name: HTCConnectService
@input: HTCHandle - HTC handle
pReq - connection details
@output: pResp - connection response
@return:
@notes: Service connections must be performed before HTCStart. User provides callback handlers
for various endpoint events.
@example:
@see also: HTCStart
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCConnectService(HTC_HANDLE HTCHandle,
HTC_SERVICE_CONNECT_REQ *pReq,
HTC_SERVICE_CONNECT_RESP *pResp);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Send an HTC packet
@function name: HTCSendPkt
@input: HTCHandle - HTC handle
pPacket - packet to send
@output:
@return: A_OK
@notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro.
This interface is fully asynchronous. On error, HTC SendPkt will
call the registered Endpoint callback to cleanup the packet.
@example:
@see also: HTCFlushEndpoint
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Stop HTC service communications
@function name: HTCStop
@input: HTCHandle - HTC handle
@output:
@return:
@notes: HTC communications is halted. All receive and pending TX packets will
be flushed.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCStop(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Shutdown HTC
@function name: HTCShutdown
@input:
@output:
@return:
@notes: This cleans up all resources allocated by HTCInit().
@example:
@see also: HTCInit
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCShutDown(void);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Flush pending TX packets
@function name: HTCFlushEndpoint
@input: HTCHandle - HTC handle
Endpoint - Endpoint to flush
Tag - flush tag
@output:
@return:
@notes: The Tag parameter is used to selectively flush packets with matching tags.
The value of 0 forces all packets to be flush regardless of tag.
@example:
@see also: HTCSendPkt
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Dump credit distribution state
@function name: HTCDumpCreditStates
@input: HTCHandle - HTC handle
@output:
@return:
@notes: This dumps all credit distribution information to the debugger
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCDumpCreditStates(HTC_HANDLE HTCHandle);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Indicate a traffic activity change on an endpoint
@function name: HTCIndicateActivityChange
@input: HTCHandle - HTC handle
Endpoint - endpoint in which activity has changed
Active - TRUE if active, FALSE if it has become inactive
@output:
@return:
@notes: This triggers the registered credit distribution function to
re-adjust credits for active/inactive endpoints.
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
A_BOOL Active);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@desc: Get endpoint statistics
@function name: HTCGetEndpointStatistics
@input: HTCHandle - HTC handle
Endpoint - Endpoint identifier
Action - action to take with statistics
@output:
pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR)
@return: TRUE if statistics profiling is enabled, otherwise FALSE.
@notes: Statistics is a compile-time option and this function may return FALSE
if HTC is not compiled with profiling.
The caller can specify the statistic "action" to take when sampling
the statistics. This includes:
HTC_EP_STAT_SAMPLE: The pStats structure is filled with the current values.
HTC_EP_STAT_SAMPLE_AND_CLEAR: The structure is filled and the current statistics
are cleared.
HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL value for
pStats
@example:
@see also:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
HTC_ENDPOINT_ID Endpoint,
HTC_ENDPOINT_STAT_ACTION Action,
HTC_ENDPOINT_STATS *pStats);
#ifdef __cplusplus
}
#endif
#endif /* _HTC_API_H_ */

View file

@ -0,0 +1,138 @@
/*
*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifndef HTC_PACKET_H_
#define HTC_PACKET_H_
#include "dl_list.h"
struct _HTC_PACKET;
typedef void (* HTC_PACKET_COMPLETION)(void *,struct _HTC_PACKET *);
typedef A_UINT16 HTC_TX_TAG;
typedef struct _HTC_TX_PACKET_INFO {
HTC_TX_TAG Tag; /* tag used to selective flush packets */
} HTC_TX_PACKET_INFO;
#define HTC_TX_PACKET_TAG_ALL 0 /* a tag of zero is reserved and used to flush ALL packets */
#define HTC_TX_PACKET_TAG_INTERNAL 1 /* internal tags start here */
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) /* user-defined tags start here */
typedef struct _HTC_RX_PACKET_INFO {
A_UINT32 Unused; /* for future use and to make compilers happy */
} HTC_RX_PACKET_INFO;
/* wrapper around endpoint-specific packets */
typedef struct _HTC_PACKET {
DL_LIST ListLink; /* double link */
void *pPktContext; /* caller's per packet specific context */
A_UINT8 *pBufferStart; /* the true buffer start , the caller can
store the real buffer start here. In
receive callbacks, the HTC layer sets pBuffer
to the start of the payload past the header. This
field allows the caller to reset pBuffer when it
recycles receive packets back to HTC */
/*
* Pointer to the start of the buffer. In the transmit
* direction this points to the start of the payload. In the
* receive direction, however, the buffer when queued up
* points to the start of the HTC header but when returned
* to the caller points to the start of the payload
*/
A_UINT8 *pBuffer; /* payload start (RX/TX) */
A_UINT32 BufferLength; /* length of buffer */
A_UINT32 ActualLength; /* actual length of payload */
int Endpoint; /* endpoint that this packet was sent/recv'd from */
A_STATUS Status; /* completion status */
union {
HTC_TX_PACKET_INFO AsTx; /* Tx Packet specific info */
HTC_RX_PACKET_INFO AsRx; /* Rx Packet specific info */
} PktInfo;
/* the following fields are for internal HTC use */
HTC_PACKET_COMPLETION Completion; /* completion */
void *pContext; /* HTC private completion context */
A_UINT32 HTCReserved; /* reserved */
} HTC_PACKET;
#define COMPLETE_HTC_PACKET(p,status) \
{ \
(p)->Status = (status); \
(p)->Completion((p)->pContext,(p)); \
}
#define INIT_HTC_PACKET_INFO(p,b,len) \
{ \
(p)->pBufferStart = (b); \
(p)->BufferLength = (len); \
}
/* macro to set an initial RX packet for refilling HTC */
#define SET_HTC_PACKET_INFO_RX_REFILL(p,c,b,len,ep) \
{ \
(p)->pPktContext = (c); \
(p)->pBuffer = (b); \
(p)->pBufferStart = (b); \
(p)->BufferLength = (len); \
(p)->Endpoint = (ep); \
}
/* fast macro to recycle an RX packet that will be re-queued to HTC */
#define HTC_PACKET_RESET_RX(p) \
(p)->pBuffer = (p)->pBufferStart
/* macro to set packet parameters for TX */
#define SET_HTC_PACKET_INFO_TX(p,c,b,len,ep,tag) \
{ \
(p)->pPktContext = (c); \
(p)->pBuffer = (b); \
(p)->ActualLength = (len); \
(p)->Endpoint = (ep); \
(p)->PktInfo.AsTx.Tag = (tag); \
}
/* HTC Packet Queueing Macros */
typedef DL_LIST HTC_PACKET_QUEUE;
/* initialize queue */
#define INIT_HTC_PACKET_QUEUE(pQ) DL_LIST_INIT((pQ))
/* enqueue HTC packet to the tail of the queue */
#define HTC_PACKET_ENQUEUE(pQ,p) DL_ListInsertTail((pQ),&(p)->ListLink)
/* test if a queue is empty */
#define HTC_QUEUE_EMPTY(pQ) DL_LIST_IS_EMPTY((pQ))
/* get packet at head without removing it */
#define HTC_GET_PKT_AT_HEAD(pQ) A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(pQ)),HTC_PACKET,ListLink);
/* remove a packet from the current list it is linked to */
#define HTC_PACKET_REMOVE(p) DL_ListRemove(&(p)->ListLink)
/* dequeue an HTC packet from the head of the queue */
static INLINE HTC_PACKET *HTC_PACKET_DEQUEUE(HTC_PACKET_QUEUE *queue) {
DL_LIST *pItem = DL_ListRemoveItemFromHead(queue);
if (pItem != NULL) {
return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink);
}
return NULL;
}
#endif /*HTC_PACKET_H_*/

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __HTC_SERVICES_H__
#define __HTC_SERVICES_H__
/* Current service IDs */
typedef enum {
RSVD_SERVICE_GROUP = 0,
WMI_SERVICE_GROUP = 1,
HTC_TEST_GROUP = 254,
HTC_SERVICE_GROUP_LAST = 255
}HTC_SERVICE_GROUP_IDS;
#define MAKE_SERVICE_ID(group,index) \
(int)(((int)group << 8) | (int)(index))
/* NOTE: service ID of 0x0000 is reserved and should never be used */
#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP,1)
#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,0)
#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,1)
#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,2)
#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,3)
#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,4)
#define WMI_MAX_SERVICES 5
/* raw stream service (i.e. flash, tcmd, calibration apps) */
#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0)
#endif /*HTC_SERVICES_H_*/

View file

@ -0,0 +1,342 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
* Copyright (c) 2006 Atheros Communications, Inc.
*
* Wireless Network driver for Atheros AR6001
* All rights reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _NET80211_IEEE80211_H_
#define _NET80211_IEEE80211_H_
#include "athstartpack.h"
/*
* 802.11 protocol definitions.
*/
#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
/* is 802.11 address multicast/broadcast? */
#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01)
#define IEEE80211_ADDR_EQ(addr1, addr2) \
(A_MEMCMP(addr1, addr2, IEEE80211_ADDR_LEN) == 0)
#define IEEE80211_KEYBUF_SIZE 16
#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx and rx */
/*
* NB: these values are ordered carefully; there are lots of
* of implications in any reordering. In particular beware
* that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY.
*/
#define IEEE80211_CIPHER_WEP 0
#define IEEE80211_CIPHER_TKIP 1
#define IEEE80211_CIPHER_AES_OCB 2
#define IEEE80211_CIPHER_AES_CCM 3
#define IEEE80211_CIPHER_CKIP 5
#define IEEE80211_CIPHER_CCKM_KRK 6
#define IEEE80211_CIPHER_NONE 7 /* pseudo value */
#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1)
#define IEEE80211_IS_VALID_WEP_CIPHER_LEN(len) \
(((len) == 5) || ((len) == 13) || ((len) == 16))
/*
* generic definitions for IEEE 802.11 frames
*/
PREPACK struct ieee80211_frame {
A_UINT8 i_fc[2];
A_UINT8 i_dur[2];
A_UINT8 i_addr1[IEEE80211_ADDR_LEN];
A_UINT8 i_addr2[IEEE80211_ADDR_LEN];
A_UINT8 i_addr3[IEEE80211_ADDR_LEN];
A_UINT8 i_seq[2];
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
/* see below */
} POSTPACK;
#define IEEE80211_FC0_VERSION_MASK 0x03
#define IEEE80211_FC0_VERSION_SHIFT 0
#define IEEE80211_FC0_VERSION_0 0x00
#define IEEE80211_FC0_TYPE_MASK 0x0c
#define IEEE80211_FC0_TYPE_SHIFT 2
#define IEEE80211_FC0_TYPE_MGT 0x00
#define IEEE80211_FC0_TYPE_CTL 0x04
#define IEEE80211_FC0_TYPE_DATA 0x08
#define IEEE80211_FC0_SUBTYPE_MASK 0xf0
#define IEEE80211_FC0_SUBTYPE_SHIFT 4
/* for TYPE_MGT */
#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00
#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10
#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20
#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30
#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40
#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50
#define IEEE80211_FC0_SUBTYPE_BEACON 0x80
#define IEEE80211_FC0_SUBTYPE_ATIM 0x90
#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0
#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0
#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0
/* for TYPE_CTL */
#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0
#define IEEE80211_FC0_SUBTYPE_RTS 0xb0
#define IEEE80211_FC0_SUBTYPE_CTS 0xc0
#define IEEE80211_FC0_SUBTYPE_ACK 0xd0
#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0
#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0
/* for TYPE_DATA (bit combination) */
#define IEEE80211_FC0_SUBTYPE_DATA 0x00
#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10
#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20
#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30
#define IEEE80211_FC0_SUBTYPE_NODATA 0x40
#define IEEE80211_FC0_SUBTYPE_CFACK 0x50
#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60
#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70
#define IEEE80211_FC0_SUBTYPE_QOS 0x80
#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0
#define IEEE80211_FC1_DIR_MASK 0x03
#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */
#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */
#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */
#define IEEE80211_FC1_MORE_FRAG 0x04
#define IEEE80211_FC1_RETRY 0x08
#define IEEE80211_FC1_PWR_MGT 0x10
#define IEEE80211_FC1_MORE_DATA 0x20
#define IEEE80211_FC1_WEP 0x40
#define IEEE80211_FC1_ORDER 0x80
#define IEEE80211_SEQ_FRAG_MASK 0x000f
#define IEEE80211_SEQ_FRAG_SHIFT 0
#define IEEE80211_SEQ_SEQ_MASK 0xfff0
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_NWID_LEN 32
/*
* 802.11 rate set.
*/
#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
#define WMM_NUM_AC 4 /* 4 AC categories */
#define WMM_PARAM_ACI_M 0x60 /* Mask for ACI field */
#define WMM_PARAM_ACI_S 5 /* Shift for ACI field */
#define WMM_PARAM_ACM_M 0x10 /* Mask for ACM bit */
#define WMM_PARAM_ACM_S 4 /* Shift for ACM bit */
#define WMM_PARAM_AIFSN_M 0x0f /* Mask for aifsn field */
#define WMM_PARAM_LOGCWMIN_M 0x0f /* Mask for CwMin field (in log) */
#define WMM_PARAM_LOGCWMAX_M 0xf0 /* Mask for CwMax field (in log) */
#define WMM_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */
#define WMM_AC_TO_TID(_ac) ( \
((_ac) == WMM_AC_VO) ? 6 : \
((_ac) == WMM_AC_VI) ? 5 : \
((_ac) == WMM_AC_BK) ? 1 : \
0)
#define TID_TO_WMM_AC(_tid) ( \
((_tid) < 1) ? WMM_AC_BE : \
((_tid) < 3) ? WMM_AC_BK : \
((_tid) < 6) ? WMM_AC_VI : \
WMM_AC_VO)
/*
* Management information element payloads.
*/
enum {
IEEE80211_ELEMID_SSID = 0,
IEEE80211_ELEMID_RATES = 1,
IEEE80211_ELEMID_FHPARMS = 2,
IEEE80211_ELEMID_DSPARMS = 3,
IEEE80211_ELEMID_CFPARMS = 4,
IEEE80211_ELEMID_TIM = 5,
IEEE80211_ELEMID_IBSSPARMS = 6,
IEEE80211_ELEMID_COUNTRY = 7,
IEEE80211_ELEMID_CHALLENGE = 16,
/* 17-31 reserved for challenge text extension */
IEEE80211_ELEMID_PWRCNSTR = 32,
IEEE80211_ELEMID_PWRCAP = 33,
IEEE80211_ELEMID_TPCREQ = 34,
IEEE80211_ELEMID_TPCREP = 35,
IEEE80211_ELEMID_SUPPCHAN = 36,
IEEE80211_ELEMID_CHANSWITCH = 37,
IEEE80211_ELEMID_MEASREQ = 38,
IEEE80211_ELEMID_MEASREP = 39,
IEEE80211_ELEMID_QUIET = 40,
IEEE80211_ELEMID_IBSSDFS = 41,
IEEE80211_ELEMID_ERP = 42,
IEEE80211_ELEMID_RSN = 48,
IEEE80211_ELEMID_XRATES = 50,
IEEE80211_ELEMID_TPC = 150,
IEEE80211_ELEMID_CCKM = 156,
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
};
#define ATH_OUI 0x7f0300 /* Atheros OUI */
#define ATH_OUI_TYPE 0x01
#define ATH_OUI_SUBTYPE 0x01
#define ATH_OUI_VERSION 0x00
#define WPA_OUI 0xf25000
#define WPA_OUI_TYPE 0x01
#define WPA_VERSION 1 /* current supported version */
#define WPA_CSE_NULL 0x00
#define WPA_CSE_WEP40 0x01
#define WPA_CSE_TKIP 0x02
#define WPA_CSE_CCMP 0x04
#define WPA_CSE_WEP104 0x05
#define WPA_ASE_NONE 0x00
#define WPA_ASE_8021X_UNSPEC 0x01
#define WPA_ASE_8021X_PSK 0x02
#define RSN_OUI 0xac0f00
#define RSN_VERSION 1 /* current supported version */
#define RSN_CSE_NULL 0x00
#define RSN_CSE_WEP40 0x01
#define RSN_CSE_TKIP 0x02
#define RSN_CSE_WRAP 0x03
#define RSN_CSE_CCMP 0x04
#define RSN_CSE_WEP104 0x05
#define RSN_ASE_NONE 0x00
#define RSN_ASE_8021X_UNSPEC 0x01
#define RSN_ASE_8021X_PSK 0x02
#define RSN_CAP_PREAUTH 0x01
#define WMM_OUI 0xf25000
#define WMM_OUI_TYPE 0x02
#define WMM_INFO_OUI_SUBTYPE 0x00
#define WMM_PARAM_OUI_SUBTYPE 0x01
#define WMM_VERSION 1
/* WMM stream classes */
#define WMM_NUM_AC 4
#define WMM_AC_BE 0 /* best effort */
#define WMM_AC_BK 1 /* background */
#define WMM_AC_VI 2 /* video */
#define WMM_AC_VO 3 /* voice */
/* TSPEC related */
#define ACTION_CATEGORY_CODE_TSPEC 17
#define ACTION_CODE_TSPEC_ADDTS 0
#define ACTION_CODE_TSPEC_ADDTS_RESP 1
#define ACTION_CODE_TSPEC_DELTS 2
typedef enum {
TSPEC_STATUS_CODE_ADMISSION_ACCEPTED = 0,
TSPEC_STATUS_CODE_ADDTS_INVALID_PARAMS = 0x1,
TSPEC_STATUS_CODE_ADDTS_REQUEST_REFUSED = 0x3,
TSPEC_STATUS_CODE_UNSPECIFIED_QOS_RELATED_FAILURE = 0xC8,
TSPEC_STATUS_CODE_REQUESTED_REFUSED_POLICY_CONFIGURATION = 0xC9,
TSPEC_STATUS_CODE_INSUFFCIENT_BANDWIDTH = 0xCA,
TSPEC_STATUS_CODE_INVALID_PARAMS = 0xCB,
TSPEC_STATUS_CODE_DELTS_SENT = 0x30,
TSPEC_STATUS_CODE_DELTS_RECV = 0x31,
} TSPEC_STATUS_CODE;
/*
* WMM/802.11e Tspec Element
*/
typedef PREPACK struct wmm_tspec_ie_t {
A_UINT8 elementId;
A_UINT8 len;
A_UINT8 oui[3];
A_UINT8 ouiType;
A_UINT8 ouiSubType;
A_UINT8 version;
A_UINT16 tsInfo_info;
A_UINT8 tsInfo_reserved;
A_UINT16 nominalMSDU;
A_UINT16 maxMSDU;
A_UINT32 minServiceInt;
A_UINT32 maxServiceInt;
A_UINT32 inactivityInt;
A_UINT32 suspensionInt;
A_UINT32 serviceStartTime;
A_UINT32 minDataRate;
A_UINT32 meanDataRate;
A_UINT32 peakDataRate;
A_UINT32 maxBurstSize;
A_UINT32 delayBound;
A_UINT32 minPhyRate;
A_UINT16 sba;
A_UINT16 mediumTime;
} POSTPACK WMM_TSPEC_IE;
/*
* BEACON management packets
*
* octet timestamp[8]
* octet beacon interval[2]
* octet capability information[2]
* information element
* octet elemid
* octet length
* octet information[length]
*/
#define IEEE80211_BEACON_INTERVAL(beacon) \
((beacon)[8] | ((beacon)[9] << 8))
#define IEEE80211_BEACON_CAPABILITY(beacon) \
((beacon)[10] | ((beacon)[11] << 8))
#define IEEE80211_CAPINFO_ESS 0x0001
#define IEEE80211_CAPINFO_IBSS 0x0002
#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004
#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008
#define IEEE80211_CAPINFO_PRIVACY 0x0010
#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020
#define IEEE80211_CAPINFO_PBCC 0x0040
#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080
/* bits 8-9 are reserved */
#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400
#define IEEE80211_CAPINFO_APSD 0x0800
/* bit 12 is reserved */
#define IEEE80211_CAPINFO_DSSSOFDM 0x2000
/* bits 14-15 are reserved */
/*
* Authentication Modes
*/
enum ieee80211_authmode {
IEEE80211_AUTH_NONE = 0,
IEEE80211_AUTH_OPEN = 1,
IEEE80211_AUTH_SHARED = 2,
IEEE80211_AUTH_8021X = 3,
IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
/* NB: these are used only for ioctls */
IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x */
IEEE80211_AUTH_WPA_PSK = 6, /* WPA/RSN w/ PSK */
IEEE80211_AUTH_WPA_CCKM = 7, /* WPA/RSN IE w/ CCKM */
};
#include "athendpack.h"
#endif /* _NET80211_IEEE80211_H_ */

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/os/linux/include/ieee80211_ioctl.h#1 $
*/
#ifndef _IEEE80211_IOCTL_H_
#define _IEEE80211_IOCTL_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Extracted from the MADWIFI net80211/ieee80211_ioctl.h
*/
/*
* WPA/RSN get/set key request. Specify the key/cipher
* type and whether the key is to be used for sending and/or
* receiving. The key index should be set only when working
* with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
* Otherwise a unicast/pairwise key is specified by the bssid
* (on a station) or mac address (on an ap). They key length
* must include any MIC key data; otherwise it should be no
more than IEEE80211_KEYBUF_SIZE.
*/
struct ieee80211req_key {
u_int8_t ik_type; /* key/cipher type */
u_int8_t ik_pad;
u_int16_t ik_keyix; /* key index */
u_int8_t ik_keylen; /* key length in bytes */
u_int8_t ik_flags;
#define IEEE80211_KEY_XMIT 0x01
#define IEEE80211_KEY_RECV 0x02
#define IEEE80211_KEY_DEFAULT 0x80 /* default xmit key */
u_int8_t ik_macaddr[IEEE80211_ADDR_LEN];
u_int64_t ik_keyrsc; /* key receive sequence counter */
u_int64_t ik_keytsc; /* key transmit sequence counter */
u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
};
/*
* Delete a key either by index or address. Set the index
* to IEEE80211_KEYIX_NONE when deleting a unicast key.
*/
struct ieee80211req_del_key {
u_int8_t idk_keyix; /* key index */
u_int8_t idk_macaddr[IEEE80211_ADDR_LEN];
};
/*
* MLME state manipulation request. IEEE80211_MLME_ASSOC
* only makes sense when operating as a station. The other
* requests can be used when operating as a station or an
* ap (to effect a station).
*/
struct ieee80211req_mlme {
u_int8_t im_op; /* operation to perform */
#define IEEE80211_MLME_ASSOC 1 /* associate station */
#define IEEE80211_MLME_DISASSOC 2 /* disassociate station */
#define IEEE80211_MLME_DEAUTH 3 /* deauthenticate station */
#define IEEE80211_MLME_AUTHORIZE 4 /* authorize station */
#define IEEE80211_MLME_UNAUTHORIZE 5 /* unauthorize station */
u_int16_t im_reason; /* 802.11 reason code */
u_int8_t im_macaddr[IEEE80211_ADDR_LEN];
};
struct ieee80211req_addpmkid {
u_int8_t pi_bssid[IEEE80211_ADDR_LEN];
u_int8_t pi_enable;
u_int8_t pi_pmkid[16];
};
#define AUTH_ALG_OPEN_SYSTEM 0x01
#define AUTH_ALG_SHARED_KEY 0x02
#define AUTH_ALG_LEAP 0x04
struct ieee80211req_authalg {
u_int8_t auth_alg;
};
/*
* Request to add an IE to a Management Frame
*/
enum{
IEEE80211_APPIE_FRAME_BEACON = 0,
IEEE80211_APPIE_FRAME_PROBE_REQ = 1,
IEEE80211_APPIE_FRAME_PROBE_RESP = 2,
IEEE80211_APPIE_FRAME_ASSOC_REQ = 3,
IEEE80211_APPIE_FRAME_ASSOC_RESP = 4,
IEEE80211_APPIE_NUM_OF_FRAME = 5
};
/*
* The Maximum length of the IE that can be added to a Management frame
*/
#define IEEE80211_APPIE_FRAME_MAX_LEN 78
struct ieee80211req_getset_appiebuf {
u_int32_t app_frmtype; /* management frame type for which buffer is added */
u_int32_t app_buflen; /*application supplied buffer length */
u_int8_t app_buf[];
};
/*
* The following definitions are used by an application to set filter
* for receiving management frames
*/
enum {
IEEE80211_FILTER_TYPE_BEACON = 0x1,
IEEE80211_FILTER_TYPE_PROBE_REQ = 0x2,
IEEE80211_FILTER_TYPE_PROBE_RESP = 0x4,
IEEE80211_FILTER_TYPE_ASSOC_REQ = 0x8,
IEEE80211_FILTER_TYPE_ASSOC_RESP = 0x10,
IEEE80211_FILTER_TYPE_AUTH = 0x20,
IEEE80211_FILTER_TYPE_DEAUTH = 0x40,
IEEE80211_FILTER_TYPE_DISASSOC = 0x80,
IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */
};
struct ieee80211req_set_filter {
u_int32_t app_filterype; /* management frame filter type */
};
enum {
IEEE80211_PARAM_AUTHMODE = 3, /* Authentication Mode */
IEEE80211_PARAM_MCASTCIPHER = 5,
IEEE80211_PARAM_MCASTKEYLEN = 6, /* multicast key length */
IEEE80211_PARAM_UCASTCIPHER = 8,
IEEE80211_PARAM_UCASTKEYLEN = 9, /* unicast key length */
IEEE80211_PARAM_WPA = 10, /* WPA mode (0,1,2) */
IEEE80211_PARAM_ROAMING = 12, /* roaming mode */
IEEE80211_PARAM_PRIVACY = 13, /* privacy invoked */
IEEE80211_PARAM_COUNTERMEASURES = 14, /* WPA/TKIP countermeasures */
IEEE80211_PARAM_DROPUNENCRYPTED = 15, /* discard unencrypted frames */
};
/*
* Values for IEEE80211_PARAM_WPA
*/
#define WPA_MODE_WPA1 1
#define WPA_MODE_WPA2 2
#define WPA_MODE_AUTO 3
#define WPA_MODE_NONE 4
#ifdef __cplusplus
}
#endif
#endif /* _IEEE80211_IOCTL_H_ */

View file

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
* Copyright (c) 2006 Atheros Communications, Inc.
*
* Wireless Network driver for Atheros AR6001
* All rights reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _IEEE80211_NODE_H_
#define _IEEE80211_NODE_H_
/*
* Node locking definitions.
*/
#define IEEE80211_NODE_LOCK_INIT(_nt) A_MUTEX_INIT(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_LOCK_DESTROY(_nt)
#define IEEE80211_NODE_LOCK(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_UNLOCK(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_LOCK_BH(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_UNLOCK_BH(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
#define IEEE80211_NODE_LOCK_ASSERT(_nt)
/*
* Node reference counting definitions.
*
* ieee80211_node_initref initialize the reference count to 1
* ieee80211_node_incref add a reference
* ieee80211_node_decref remove a reference
* ieee80211_node_dectestref remove a reference and return 1 if this
* is the last reference, otherwise 0
* ieee80211_node_refcnt reference count for printing (only)
*/
#define ieee80211_node_initref(_ni) ((_ni)->ni_refcnt = 1)
#define ieee80211_node_incref(_ni) ((_ni)->ni_refcnt++)
#define ieee80211_node_decref(_ni) ((_ni)->ni_refcnt--)
#define ieee80211_node_dectestref(_ni) (((_ni)->ni_refcnt--) == 0)
#define ieee80211_node_refcnt(_ni) ((_ni)->ni_refcnt)
#define IEEE80211_NODE_HASHSIZE 32
/* simple hash is enough for variation of macaddr */
#define IEEE80211_NODE_HASH(addr) \
(((const A_UINT8 *)(addr))[IEEE80211_ADDR_LEN - 1] % \
IEEE80211_NODE_HASHSIZE)
/*
* Table of ieee80211_node instances. Each ieee80211com
* has at least one for holding the scan candidates.
* When operating as an access point or in ibss mode there
* is a second table for associated stations or neighbors.
*/
struct ieee80211_node_table {
void *nt_wmip; /* back reference */
A_MUTEX_T nt_nodelock; /* on node table */
struct bss *nt_node_first; /* information of all nodes */
struct bss *nt_node_last; /* information of all nodes */
struct bss *nt_hash[IEEE80211_NODE_HASHSIZE];
const char *nt_name; /* for debugging */
A_UINT32 nt_scangen; /* gen# for timeout scan */
A_TIMER nt_inact_timer;
A_UINT8 isTimerArmed; /* is the node timer armed */
};
#define WLAN_NODE_INACT_TIMEOUT_MSEC 10000
#endif /* _IEEE80211_NODE_H_ */

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef _INI_DSET_H_
#define _INI_DSET_H_
/*
* Each of these represents a WHAL INI table, which consists
* of an "address column" followed by 1 or more "value columns".
*
* Software uses the base WHAL_INI_DATA_ID+column to access a
* DataSet that holds a particular column of data.
*/
typedef enum {
WHAL_INI_DATA_ID_NULL =0,
WHAL_INI_DATA_ID_MODE_SPECIFIC =1, /* 2,3 */
WHAL_INI_DATA_ID_COMMON =4, /* 5 */
WHAL_INI_DATA_ID_BB_RFGAIN =6, /* 7,8 */
WHAL_INI_DATA_ID_ANALOG_BANK1 =9, /* 10 */
WHAL_INI_DATA_ID_ANALOG_BANK2 =11, /* 12 */
WHAL_INI_DATA_ID_ANALOG_BANK3 =13, /* 14, 15 */
WHAL_INI_DATA_ID_ANALOG_BANK6 =16, /* 17, 18 */
WHAL_INI_DATA_ID_ANALOG_BANK7 =19, /* 20 */
WHAL_INI_DATA_ID_MODE_OVERRIDES =21, /* 22,23 */
WHAL_INI_DATA_ID_COMMON_OVERRIDES =24, /* 25 */
WHAL_INI_DATA_ID_MAX =25
} WHAL_INI_DATA_ID;
typedef PREPACK struct {
A_UINT16 freqIndex; // 1 - A mode 2 - B or G mode 0 - common
A_UINT16 offset;
A_UINT32 newValue;
} POSTPACK INI_DSET_REG_OVERRIDE;
#endif

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2005 Atheros Communications, Inc.
* All rights reserved.
*
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This module contains the header files for regulatory module,
* which include the DB schema and DB values.
* $Id:
*/
#ifndef __REG_DB_H__
#define __REG_DB_H__
#include "./regulatory/reg_dbschema.h"
#include "./regulatory/reg_dbvalues.h"
#endif /* __REG_DB_H__ */

View file

@ -0,0 +1,33 @@
#ifndef __REGDUMP_H__
#define __REGDUMP_H__
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#if defined(AR6001)
#include "AR6001/AR6001_regdump.h"
#endif
#if defined(AR6002)
#include "AR6002/AR6002_regdump.h"
#endif
#if !defined(__ASSEMBLER__)
/*
* Target CPU state at the time of failure is reflected
* in a register dump, which the Host can fetch through
* the diagnostic window.
*/
struct register_dump_s {
A_UINT32 target_id; /* Target ID */
A_UINT32 assline; /* Line number (if assertion failure) */
A_UINT32 pc; /* Program Counter at time of exception */
A_UINT32 badvaddr; /* Virtual address causing exception */
CPU_exception_frame_t exc_frame; /* CPU-specific exception info */
/* Could copy top of stack here, too.... */
};
#endif /* __ASSEMBLER__ */
#endif /* __REGDUMP_H__ */

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __TARGADDRS_H__
#define __TARGADDRS_H__
#if defined(AR6001)
#include "AR6001/addrs.h"
#endif
#if defined(AR6002)
#include "AR6002/addrs.h"
#endif
/*
* AR6K option bits, to enable/disable various features.
* By default, all option bits are 0.
* These bits can be set in LOCAL_SCRATCH register 0.
*/
#define AR6K_OPTION_BMI_DISABLE 0x01 /* Disable BMI comm with Host */
#define AR6K_OPTION_SERIAL_ENABLE 0x02 /* Enable serial port msgs */
#define AR6K_OPTION_WDT_DISABLE 0x04 /* WatchDog Timer override */
#define AR6K_OPTION_SLEEP_DISABLE 0x08 /* Disable system sleep */
#define AR6K_OPTION_STOP_BOOT 0x10 /* Stop boot processes (for ATE) */
#define AR6K_OPTION_ENABLE_NOANI 0x20 /* Operate without ANI */
#define AR6K_OPTION_DSET_DISABLE 0x40 /* Ignore DataSets */
#define AR6K_OPTION_IGNORE_FLASH 0x80 /* Ignore flash during bootup */
/*
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
* host_interest structure. It must match the address of the _host_interest
* symbol (see linker script).
*
* Host Interest is shared between Host and Target in order to coordinate
* between the two, and is intended to remain constant (with additions only
* at the end) across software releases.
*/
#define AR6001_HOST_INTEREST_ADDRESS 0x80000600
#define AR6002_HOST_INTEREST_ADDRESS 0x00500400
#define HOST_INTEREST_MAX_SIZE 0x100
#if !defined(__ASSEMBLER__)
struct register_dump_s;
struct dbglog_hdr_s;
/*
* These are items that the Host may need to access
* via BMI or via the Diagnostic Window. The position
* of items in this structure must remain constant
* across firmware revisions!
*
* Types for each item must be fixed size across
* target and host platforms.
*
* More items may be added at the end.
*/
struct host_interest_s {
/*
* Pointer to application-defined area, if any.
* Set by Target application during startup.
*/
A_UINT32 hi_app_host_interest; /* 0x00 */
/* Pointer to register dump area, valid after Target crash. */
A_UINT32 hi_failure_state; /* 0x04 */
/* Pointer to debug logging header */
A_UINT32 hi_dbglog_hdr; /* 0x08 */
/* Indicates whether or not flash is present on Target.
* NB: flash_is_present indicator is here not just
* because it might be of interest to the Host; but
* also because it's set early on by Target's startup
* asm code and we need it to have a special RAM address
* so that it doesn't get reinitialized with the rest
* of data.
*/
A_UINT32 hi_flash_is_present; /* 0x0c */
/*
* General-purpose flag bits, similar to AR6000_OPTION_* flags.
* Can be used by application rather than by OS.
*/
A_UINT32 hi_option_flag; /* 0x10 */
/*
* Boolean that determines whether or not to
* display messages on the serial port.
*/
A_UINT32 hi_serial_enable; /* 0x14 */
/* Start address of Flash DataSet index, if any */
A_UINT32 hi_dset_list_head; /* 0x18 */
/* Override Target application start address */
A_UINT32 hi_app_start; /* 0x1c */
/* Clock and voltage tuning */
A_UINT32 hi_skip_clock_init; /* 0x20 */
A_UINT32 hi_core_clock_setting; /* 0x24 */
A_UINT32 hi_cpu_clock_setting; /* 0x28 */
A_UINT32 hi_system_sleep_setting; /* 0x2c */
A_UINT32 hi_xtal_control_setting; /* 0x30 */
A_UINT32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
A_UINT32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
A_UINT32 hi_ref_voltage_trim_setting; /* 0x3c */
A_UINT32 hi_clock_info; /* 0x40 */
/*
* Flash configuration overrides, used only
* when firmware is not executing from flash.
* (When using flash, modify the global variables
* with equivalent names.)
*/
A_UINT32 hi_bank0_addr_value; /* 0x44 */
A_UINT32 hi_bank0_read_value; /* 0x48 */
A_UINT32 hi_bank0_write_value; /* 0x4c */
A_UINT32 hi_bank0_config_value; /* 0x50 */
/* Pointer to Board Data */
A_UINT32 hi_board_data; /* 0x54 */
A_UINT32 hi_board_data_initialized; /* 0x58 */
A_UINT32 hi_dset_RAM_index_table; /* 0x5c */
A_UINT32 hi_desired_baud_rate; /* 0x60 */
A_UINT32 hi_dbglog_config; /* 0x64 */
A_UINT32 hi_end_RAM_reserve_sz; /* 0x68 */
A_UINT32 hi_mbox_io_block_sz; /* 0x6c */
A_UINT32 hi_num_bpatch_streams; /* 0x70 */
A_UINT32 hi_mbox_isr_yield_limit; /* 0x74 */
A_UINT32 hi_refclk_hz; /* 0x78 */
};
/* Bits defined in hi_option_flag */
#define HI_OPTION_TIMER_WAR 1 /* not really used */
/*
* Intended for use by Host software, this macro returns the Target RAM
* address of any item in the host_interest structure.
* Example: target_addr = AR6001_HOST_INTEREST_ITEM_ADDRESS(hi_board_data);
*/
#define AR6001_HOST_INTEREST_ITEM_ADDRESS(item) \
((A_UINT32)&((((struct host_interest_s *)(AR6001_HOST_INTEREST_ADDRESS))->item)))
#define AR6002_HOST_INTEREST_ITEM_ADDRESS(item) \
((A_UINT32)&((((struct host_interest_s *)(AR6002_HOST_INTEREST_ADDRESS))->item)))
#endif /* !__ASSEMBLER__ */
#endif /* __TARGADDRS_H__ */

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef TESTCMD_H_
#define TESTCMD_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ZEROES_PATTERN = 0,
ONES_PATTERN,
REPEATING_10,
PN7_PATTERN,
PN9_PATTERN,
PN15_PATTERN
}TX_DATA_PATTERN;
/* Continous tx
mode : TCMD_CONT_TX_OFF - Disabling continous tx
TCMD_CONT_TX_SINE - Enable continuous unmodulated tx
TCMD_CONT_TX_FRAME- Enable continuous modulated tx
freq : Channel freq in Mhz. (e.g 2412 for channel 1 in 11 g)
dataRate: 0 - 1 Mbps
1 - 2 Mbps
2 - 5.5 Mbps
3 - 11 Mbps
4 - 6 Mbps
5 - 9 Mbps
6 - 12 Mbps
7 - 18 Mbps
8 - 24 Mbps
9 - 36 Mbps
10 - 28 Mbps
11 - 54 Mbps
txPwr: Tx power in dBm[5 -11] for unmod Tx, [5-14] for mod Tx
antenna: 1 - one antenna
2 - two antenna
Note : Enable/disable continuous tx test cmd works only when target is awake.
*/
typedef enum {
TCMD_CONT_TX_OFF = 0,
TCMD_CONT_TX_SINE,
TCMD_CONT_TX_FRAME,
TCMD_CONT_TX_TX99,
TCMD_CONT_TX_TX100
} TCMD_CONT_TX_MODE;
typedef PREPACK struct {
A_UINT32 testCmdId;
A_UINT32 mode;
A_UINT32 freq;
A_UINT32 dataRate;
A_INT32 txPwr;
A_UINT32 antenna;
A_UINT32 enANI;
A_UINT32 scramblerOff;
A_UINT32 aifsn;
A_UINT16 pktSz;
A_UINT16 txPattern;
} POSTPACK TCMD_CONT_TX;
#define TCMD_TXPATTERN_ZERONE 0x1
#define TCMD_TXPATTERN_ZERONE_DIS_SCRAMBLE 0x2
/* Continuous Rx
act: TCMD_CONT_RX_PROMIS - promiscuous mode (accept all incoming frames)
TCMD_CONT_RX_FILTER - filter mode (accept only frames with dest
address equal specified
mac address (set via act =3)
TCMD_CONT_RX_REPORT off mode (disable cont rx mode and get the
report from the last cont
Rx test)
TCMD_CONT_RX_SETMAC - set MacAddr mode (sets the MAC address for the
target. This Overrides
the default MAC address.)
*/
typedef enum {
TCMD_CONT_RX_PROMIS =0,
TCMD_CONT_RX_FILTER,
TCMD_CONT_RX_REPORT,
TCMD_CONT_RX_SETMAC
} TCMD_CONT_RX_ACT;
typedef PREPACK struct {
A_UINT32 testCmdId;
A_UINT32 act;
A_UINT32 enANI;
PREPACK union {
struct PREPACK TCMD_CONT_RX_PARA {
A_UINT32 freq;
A_UINT32 antenna;
} POSTPACK para;
struct PREPACK TCMD_CONT_RX_REPORT {
A_UINT32 totalPkt;
A_INT32 rssiInDBm;
} POSTPACK report;
struct PREPACK TCMD_CONT_RX_MAC {
A_UCHAR addr[ATH_MAC_LEN];
} POSTPACK mac;
} POSTPACK u;
} POSTPACK TCMD_CONT_RX;
/* Force sleep/wake test cmd
mode: TCMD_PM_WAKEUP - Wakeup the target
TCMD_PM_SLEEP - Force the target to sleep.
*/
typedef enum {
TCMD_PM_WAKEUP = 1, /* be consistent with target */
TCMD_PM_SLEEP
} TCMD_PM_MODE;
typedef PREPACK struct {
A_UINT32 testCmdId;
A_UINT32 mode;
} POSTPACK TCMD_PM;
typedef enum{
TCMD_CONT_TX_ID,
TCMD_CONT_RX_ID,
TCMD_PM_ID
} TCMD_ID;
typedef PREPACK union {
TCMD_CONT_TX contTx;
TCMD_CONT_RX contRx;
TCMD_PM pm ;
} POSTPACK TEST_CMD;
#ifdef __cplusplus
}
#endif
#endif /* TESTCMD_H_ */

View file

@ -0,0 +1,101 @@
#ifndef _HOST_WLAN_API_H_
#define _HOST_WLAN_API_H_
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
* This file contains the API for the host wlan module
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/wlan_api.h#1 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
struct ieee80211_node_table;
struct ieee80211_frame;
struct ieee80211_common_ie {
A_UINT16 ie_chan;
A_UINT8 *ie_tstamp;
A_UINT8 *ie_ssid;
A_UINT8 *ie_rates;
A_UINT8 *ie_xrates;
A_UINT8 *ie_country;
A_UINT8 *ie_wpa;
A_UINT8 *ie_rsn;
A_UINT8 *ie_wmm;
A_UINT8 *ie_ath;
A_UINT16 ie_capInfo;
A_UINT16 ie_beaconInt;
A_UINT8 *ie_tim;
A_UINT8 *ie_chswitch;
A_UINT8 ie_erp;
A_UINT8 *ie_wsc;
};
typedef struct bss {
A_UINT8 ni_macaddr[6];
A_UINT8 ni_snr;
A_INT16 ni_rssi;
struct bss *ni_list_next;
struct bss *ni_list_prev;
struct bss *ni_hash_next;
struct bss *ni_hash_prev;
struct ieee80211_common_ie ni_cie;
A_UINT8 *ni_buf;
struct ieee80211_node_table *ni_table;
A_UINT32 ni_refcnt;
int ni_scangen;
A_UINT32 ni_tstamp;
} bss_t;
typedef void wlan_node_iter_func(void *arg, bss_t *);
bss_t *wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size);
void wlan_node_free(bss_t *ni);
void wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
const A_UINT8 *macaddr);
bss_t *wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr);
void wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni);
void wlan_free_allnodes(struct ieee80211_node_table *nt);
void wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
void *arg);
void wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt);
void wlan_node_table_reset(struct ieee80211_node_table *nt);
void wlan_node_table_cleanup(struct ieee80211_node_table *nt);
A_STATUS wlan_parse_beacon(A_UINT8 *buf, int framelen,
struct ieee80211_common_ie *cie);
A_UINT16 wlan_ieee2freq(int chan);
A_UINT32 wlan_freq2ieee(A_UINT16 freq);
bss_t *
wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
A_UINT32 ssidLength, A_BOOL bIsWPA2);
void
wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni);
#ifdef __cplusplus
}
#endif
#endif /* _HOST_WLAN_API_H_ */

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2007 Atheros Communications, Inc.
* All rights reserved.
*
*
* $ATH_LICENSE_HOSTSDK0_C$
*
*/
#ifndef __WLAN_DSET_H__
#define __WKAN_DSET_H__
typedef PREPACK struct wow_config_dset {
A_UINT8 valid_dset;
A_UINT8 gpio_enable;
A_UINT16 gpio_pin;
} POSTPACK WOW_CONFIG_DSET;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,260 @@
#ifndef _WMI_API_H_
#define _WMI_API_H_
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
* This file contains the definitions for the Wireless Module Interface (WMI).
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/include/wmi_api.h#2 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* IP QoS Field definitions according to 802.1p
*/
#define BEST_EFFORT_PRI 0
#define BACKGROUND_PRI 1
#define EXCELLENT_EFFORT_PRI 3
#define CONTROLLED_LOAD_PRI 4
#define VIDEO_PRI 5
#define VOICE_PRI 6
#define NETWORK_CONTROL_PRI 7
#define MAX_NUM_PRI 8
#define UNDEFINED_PRI (0xff)
/* simple mapping of IP TOS field to a WMI priority stream
* this mapping was taken from the original linux driver implementation
* The operation maps the following
*
* */
#define IP_TOS_TO_WMI_PRI(tos) \
((WMI_PRI_STREAM_ID)(((tos) >> 1) & 0x03))
#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 /* 5 seconds */
struct wmi_t;
void *wmi_init(void *devt);
void wmi_qos_state_init(struct wmi_t *wmip);
void wmi_shutdown(struct wmi_t *wmip);
A_UINT16 wmi_get_mapped_qos_queue(struct wmi_t *, A_UINT8);
A_STATUS wmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf);
A_STATUS wmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, A_UINT8 msgType);
A_STATUS wmi_dot3_2_dix(struct wmi_t *wmip, void *osbuf);
A_STATUS wmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf);
A_STATUS wmi_syncpoint(struct wmi_t *wmip);
A_STATUS wmi_syncpoint_reset(struct wmi_t *wmip);
WMI_PRI_STREAM_ID wmi_get_stream_id(struct wmi_t *wmip, A_UINT8 trafficClass);
A_UINT8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, A_UINT8 dir, A_UINT8 up);
A_STATUS wmi_control_rx(struct wmi_t *wmip, void *osbuf);
void wmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg);
void wmi_free_allnodes(struct wmi_t *wmip);
bss_t *wmi_find_node(struct wmi_t *wmip, const A_UINT8 *macaddr);
typedef enum {
NO_SYNC_WMIFLAG = 0,
SYNC_BEFORE_WMIFLAG, /* transmit all queued data before cmd */
SYNC_AFTER_WMIFLAG, /* any new data waits until cmd execs */
SYNC_BOTH_WMIFLAG,
END_WMIFLAG /* end marker */
} WMI_SYNC_FLAG;
A_STATUS wmi_cmd_send(struct wmi_t *wmip, void *osbuf, WMI_COMMAND_ID cmdId,
WMI_SYNC_FLAG flag);
A_STATUS wmi_connect_cmd(struct wmi_t *wmip,
NETWORK_TYPE netType,
DOT11_AUTH_MODE dot11AuthMode,
AUTH_MODE authMode,
CRYPTO_TYPE pairwiseCrypto,
A_UINT8 pairwiseCryptoLen,
CRYPTO_TYPE groupCrypto,
A_UINT8 groupCryptoLen,
int ssidLength,
A_UCHAR *ssid,
A_UINT8 *bssid,
A_UINT16 channel,
A_UINT32 ctrl_flags);
A_STATUS wmi_reconnect_cmd(struct wmi_t *wmip,
A_UINT8 *bssid,
A_UINT16 channel);
A_STATUS wmi_disconnect_cmd(struct wmi_t *wmip);
A_STATUS wmi_getrev_cmd(struct wmi_t *wmip);
A_STATUS wmi_startscan_cmd(struct wmi_t *wmip, WMI_SCAN_TYPE scanType,
A_BOOL forceFgScan, A_BOOL isLegacy,
A_UINT32 homeDwellTime, A_UINT32 forceScanInterval);
A_STATUS wmi_scanparams_cmd(struct wmi_t *wmip, A_UINT16 fg_start_sec,
A_UINT16 fg_end_sec, A_UINT16 bg_sec,
A_UINT16 minact_chdw_msec,
A_UINT16 maxact_chdw_msec, A_UINT16 pas_chdw_msec,
A_UINT8 shScanRatio, A_UINT8 scanCtrlFlags,
A_UINT32 max_dfsch_act_time);
A_STATUS wmi_bssfilter_cmd(struct wmi_t *wmip, A_UINT8 filter, A_UINT32 ieMask);
A_STATUS wmi_probedSsid_cmd(struct wmi_t *wmip, A_UINT8 index, A_UINT8 flag,
A_UINT8 ssidLength, A_UCHAR *ssid);
A_STATUS wmi_listeninterval_cmd(struct wmi_t *wmip, A_UINT16 listenInterval, A_UINT16 listenBeacons);
A_STATUS wmi_bmisstime_cmd(struct wmi_t *wmip, A_UINT16 bmisstime, A_UINT16 bmissbeacons);
A_STATUS wmi_associnfo_cmd(struct wmi_t *wmip, A_UINT8 ieType,
A_UINT8 ieLen, A_UINT8 *ieInfo);
A_STATUS wmi_powermode_cmd(struct wmi_t *wmip, A_UINT8 powerMode);
A_STATUS wmi_ibsspmcaps_cmd(struct wmi_t *wmip, A_UINT8 pmEnable, A_UINT8 ttl,
A_UINT16 atim_windows, A_UINT16 timeout_value);
A_STATUS wmi_pmparams_cmd(struct wmi_t *wmip, A_UINT16 idlePeriod,
A_UINT16 psPollNum, A_UINT16 dtimPolicy);
A_STATUS wmi_disctimeout_cmd(struct wmi_t *wmip, A_UINT8 timeout);
A_STATUS wmi_sync_cmd(struct wmi_t *wmip, A_UINT8 syncNumber);
A_STATUS wmi_create_pstream_cmd(struct wmi_t *wmip, WMI_CREATE_PSTREAM_CMD *pstream);
A_STATUS wmi_delete_pstream_cmd(struct wmi_t *wmip, A_UINT8 trafficClass, A_UINT8 streamID);
A_STATUS wmi_set_bitrate_cmd(struct wmi_t *wmip, A_INT32 rate);
A_STATUS wmi_get_bitrate_cmd(struct wmi_t *wmip);
A_INT8 wmi_validate_bitrate(struct wmi_t *wmip, A_INT32 rate);
A_STATUS wmi_get_regDomain_cmd(struct wmi_t *wmip);
A_STATUS wmi_get_channelList_cmd(struct wmi_t *wmip);
A_STATUS wmi_set_channelParams_cmd(struct wmi_t *wmip, A_UINT8 scanParam,
WMI_PHY_MODE mode, A_INT8 numChan,
A_UINT16 *channelList);
A_STATUS wmi_set_snr_threshold_params(struct wmi_t *wmip,
WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
A_STATUS wmi_set_rssi_threshold_params(struct wmi_t *wmip,
WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
A_STATUS wmi_clr_rssi_snr(struct wmi_t *wmip);
A_STATUS wmi_set_lq_threshold_params(struct wmi_t *wmip,
WMI_LQ_THRESHOLD_PARAMS_CMD *lqCmd);
A_STATUS wmi_set_rts_cmd(struct wmi_t *wmip, A_UINT16 threshold);
A_STATUS wmi_set_lpreamble_cmd(struct wmi_t *wmip, A_UINT8 status);
A_STATUS wmi_set_error_report_bitmask(struct wmi_t *wmip, A_UINT32 bitmask);
A_STATUS wmi_get_challenge_resp_cmd(struct wmi_t *wmip, A_UINT32 cookie,
A_UINT32 source);
A_STATUS wmi_config_debug_module_cmd(struct wmi_t *wmip, A_UINT16 mmask,
A_UINT16 tsr, A_BOOL rep, A_UINT16 size,
A_UINT32 valid);
A_STATUS wmi_get_stats_cmd(struct wmi_t *wmip);
A_STATUS wmi_addKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex,
CRYPTO_TYPE keyType, A_UINT8 keyUsage,
A_UINT8 keyLength,A_UINT8 *keyRSC,
A_UINT8 *keyMaterial, A_UINT8 key_op_ctrl,
WMI_SYNC_FLAG sync_flag);
A_STATUS wmi_add_krk_cmd(struct wmi_t *wmip, A_UINT8 *krk);
A_STATUS wmi_delete_krk_cmd(struct wmi_t *wmip);
A_STATUS wmi_deleteKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex);
A_STATUS wmi_set_akmp_params_cmd(struct wmi_t *wmip,
WMI_SET_AKMP_PARAMS_CMD *akmpParams);
A_STATUS wmi_get_pmkid_list_cmd(struct wmi_t *wmip);
A_STATUS wmi_set_pmkid_list_cmd(struct wmi_t *wmip,
WMI_SET_PMKID_LIST_CMD *pmkInfo);
A_STATUS wmi_set_txPwr_cmd(struct wmi_t *wmip, A_UINT8 dbM);
A_STATUS wmi_get_txPwr_cmd(struct wmi_t *wmip);
A_STATUS wmi_switch_radio(struct wmi_t *wmip, A_UINT8 on);
A_STATUS wmi_addBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex, A_UINT8 *bssid);
A_STATUS wmi_deleteBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex);
A_STATUS wmi_set_tkip_countermeasures_cmd(struct wmi_t *wmip, A_BOOL en);
A_STATUS wmi_setPmkid_cmd(struct wmi_t *wmip, A_UINT8 *bssid, A_UINT8 *pmkId,
A_BOOL set);
A_STATUS wmi_set_access_params_cmd(struct wmi_t *wmip, A_UINT16 txop,
A_UINT8 eCWmin, A_UINT8 eCWmax,
A_UINT8 aifsn);
A_STATUS wmi_set_retry_limits_cmd(struct wmi_t *wmip, A_UINT8 frameType,
A_UINT8 trafficClass, A_UINT8 maxRetries,
A_UINT8 enableNotify);
void wmi_get_current_bssid(struct wmi_t *wmip, A_UINT8 *bssid);
A_STATUS wmi_get_roam_tbl_cmd(struct wmi_t *wmip);
A_STATUS wmi_get_roam_data_cmd(struct wmi_t *wmip, A_UINT8 roamDataType);
A_STATUS wmi_set_roam_ctrl_cmd(struct wmi_t *wmip, WMI_SET_ROAM_CTRL_CMD *p,
A_UINT8 size);
A_STATUS wmi_set_powersave_timers_cmd(struct wmi_t *wmip,
WMI_POWERSAVE_TIMERS_POLICY_CMD *pCmd,
A_UINT8 size);
A_STATUS wmi_set_opt_mode_cmd(struct wmi_t *wmip, A_UINT8 optMode);
A_STATUS wmi_opt_tx_frame_cmd(struct wmi_t *wmip,
A_UINT8 frmType,
A_UINT8 *dstMacAddr,
A_UINT8 *bssid,
A_UINT16 optIEDataLen,
A_UINT8 *optIEData);
A_STATUS wmi_set_adhoc_bconIntvl_cmd(struct wmi_t *wmip, A_UINT16 intvl);
A_STATUS wmi_set_voice_pkt_size_cmd(struct wmi_t *wmip, A_UINT16 voicePktSize);
A_STATUS wmi_set_max_sp_len_cmd(struct wmi_t *wmip, A_UINT8 maxSpLen);
A_UINT8 convert_userPriority_to_trafficClass(A_UINT8 userPriority);
A_UINT8 wmi_get_power_mode_cmd(struct wmi_t *wmip);
A_STATUS wmi_verify_tspec_params(WMI_CREATE_PSTREAM_CMD *pCmd, A_BOOL tspecCompliance);
#ifdef CONFIG_HOST_TCMD_SUPPORT
A_STATUS wmi_test_cmd(struct wmi_t *wmip, A_UINT8 *buf, A_UINT32 len);
#endif
A_STATUS wmi_set_bt_status_cmd(struct wmi_t *wmip, A_UINT8 streamType, A_UINT8 status);
A_STATUS wmi_set_bt_params_cmd(struct wmi_t *wmip, WMI_SET_BT_PARAMS_CMD* cmd);
/*
* This function is used to configure the fix rates mask to the target.
*/
A_STATUS wmi_set_fixrates_cmd(struct wmi_t *wmip, A_INT16 fixRatesMask);
A_STATUS wmi_get_ratemask_cmd(struct wmi_t *wmip);
A_STATUS wmi_set_authmode_cmd(struct wmi_t *wmip, A_UINT8 mode);
A_STATUS wmi_set_reassocmode_cmd(struct wmi_t *wmip, A_UINT8 mode);
A_STATUS wmi_set_wmm_cmd(struct wmi_t *wmip, WMI_WMM_STATUS status);
A_STATUS wmi_set_wmm_txop(struct wmi_t *wmip, WMI_TXOP_CFG txEnable);
A_STATUS wmi_get_keepalive_configured(struct wmi_t *wmip);
A_UINT8 wmi_get_keepalive_cmd(struct wmi_t *wmip);
A_STATUS wmi_set_keepalive_cmd(struct wmi_t *wmip, A_UINT8 keepaliveInterval);
A_STATUS wmi_set_appie_cmd(struct wmi_t *wmip, A_UINT8 mgmtFrmType,
A_UINT8 ieLen,A_UINT8 *ieInfo);
A_STATUS wmi_set_halparam_cmd(struct wmi_t *wmip, A_UINT8 *cmd, A_UINT16 dataLen);
A_INT32 wmi_get_rate(A_INT8 rateindex);
/*Wake on Wireless WMI commands*/
A_STATUS wmi_set_host_sleep_mode_cmd(struct wmi_t *wmip, WMI_SET_HOST_SLEEP_MODE_CMD *cmd);
A_STATUS wmi_set_wow_mode_cmd(struct wmi_t *wmip, WMI_SET_WOW_MODE_CMD *cmd);
A_STATUS wmi_get_wow_list_cmd(struct wmi_t *wmip, WMI_GET_WOW_LIST_CMD *cmd);
A_STATUS wmi_add_wow_pattern_cmd(struct wmi_t *wmip,
WMI_ADD_WOW_PATTERN_CMD *cmd, A_UINT8* pattern, A_UINT8* mask, A_UINT8 pattern_size);
A_STATUS wmi_del_wow_pattern_cmd(struct wmi_t *wmip,
WMI_DEL_WOW_PATTERN_CMD *cmd);
A_STATUS wmi_set_wsc_status_cmd(struct wmi_t *wmip, A_UINT32 status);
bss_t *
wmi_find_Ssidnode (struct wmi_t *wmip, A_UCHAR *pSsid,
A_UINT32 ssidLength, A_BOOL bIsWPA2);
void
wmi_node_return (struct wmi_t *wmip, bss_t *bss);
#ifdef __cplusplus
}
#endif
#endif /* _WMI_API_H_ */

View file

@ -0,0 +1,233 @@
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
*
* $ATH_LICENSE_HOSTSDK0_C$
*
* This file contains extensions of the WMI protocol specified in the
* Wireless Module Interface (WMI). It includes definitions of all
* extended commands and events. Extensions include useful commands
* that are not directly related to wireless activities. They may
* be hardware-specific, and they might not be supported on all
* implementations.
*
* Extended WMIX commands are encapsulated in a WMI message with
* cmd=WMI_EXTENSION_CMD.
*
*/
#ifndef _WMIX_H_
#define _WMIX_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ATH_TARGET
#include "athstartpack.h"
#endif
#include "dbglog.h"
/*
* Extended WMI commands are those that are needed during wireless
* operation, but which are not really wireless commands. This allows,
* for instance, platform-specific commands. Extended WMI commands are
* embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID.
* Extended WMI events are similarly embedded in a WMI event message with
* WMI_EVENT_ID=WMI_EXTENSION_EVENTID.
*/
typedef PREPACK struct {
A_UINT32 commandId;
} POSTPACK WMIX_CMD_HDR;
typedef enum {
WMIX_DSETOPEN_REPLY_CMDID = 0x2001,
WMIX_DSETDATA_REPLY_CMDID,
WMIX_GPIO_OUTPUT_SET_CMDID,
WMIX_GPIO_INPUT_GET_CMDID,
WMIX_GPIO_REGISTER_SET_CMDID,
WMIX_GPIO_REGISTER_GET_CMDID,
WMIX_GPIO_INTR_ACK_CMDID,
WMIX_HB_CHALLENGE_RESP_CMDID,
WMIX_DBGLOG_CFG_MODULE_CMDID,
} WMIX_COMMAND_ID;
typedef enum {
WMIX_DSETOPENREQ_EVENTID = 0x3001,
WMIX_DSETCLOSE_EVENTID,
WMIX_DSETDATAREQ_EVENTID,
WMIX_GPIO_INTR_EVENTID,
WMIX_GPIO_DATA_EVENTID,
WMIX_GPIO_ACK_EVENTID,
WMIX_HB_CHALLENGE_RESP_EVENTID,
WMIX_DBGLOG_EVENTID,
} WMIX_EVENT_ID;
/*
* =============DataSet support=================
*/
/*
* WMIX_DSETOPENREQ_EVENTID
* DataSet Open Request Event
*/
typedef PREPACK struct {
A_UINT32 dset_id;
A_UINT32 targ_dset_handle; /* echo'ed, not used by Host, */
A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */
A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */
} POSTPACK WMIX_DSETOPENREQ_EVENT;
/*
* WMIX_DSETCLOSE_EVENTID
* DataSet Close Event
*/
typedef PREPACK struct {
A_UINT32 access_cookie;
} POSTPACK WMIX_DSETCLOSE_EVENT;
/*
* WMIX_DSETDATAREQ_EVENTID
* DataSet Data Request Event
*/
typedef PREPACK struct {
A_UINT32 access_cookie;
A_UINT32 offset;
A_UINT32 length;
A_UINT32 targ_buf; /* echo'ed, not used by Host, */
A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */
A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */
} POSTPACK WMIX_DSETDATAREQ_EVENT;
typedef PREPACK struct {
A_UINT32 status;
A_UINT32 targ_dset_handle;
A_UINT32 targ_reply_fn;
A_UINT32 targ_reply_arg;
A_UINT32 access_cookie;
A_UINT32 size;
A_UINT32 version;
} POSTPACK WMIX_DSETOPEN_REPLY_CMD;
typedef PREPACK struct {
A_UINT32 status;
A_UINT32 targ_buf;
A_UINT32 targ_reply_fn;
A_UINT32 targ_reply_arg;
A_UINT32 length;
A_UINT8 buf[1];
} POSTPACK WMIX_DSETDATA_REPLY_CMD;
/*
* =============GPIO support=================
* All masks are 18-bit masks with bit N operating on GPIO pin N.
*/
#include "gpio.h"
/*
* Set GPIO pin output state.
* In order for output to be driven, a pin must be enabled for output.
* This can be done during initialization through the GPIO Configuration
* DataSet, or during operation with the enable_mask.
*
* If a request is made to simultaneously set/clear or set/disable or
* clear/disable or disable/enable, results are undefined.
*/
typedef PREPACK struct {
A_UINT32 set_mask; /* pins to set */
A_UINT32 clear_mask; /* pins to clear */
A_UINT32 enable_mask; /* pins to enable for output */
A_UINT32 disable_mask; /* pins to disable/tristate */
} POSTPACK WMIX_GPIO_OUTPUT_SET_CMD;
/*
* Set a GPIO register. For debug/exceptional cases.
* Values for gpioreg_id are GPIO_REGISTER_IDs, defined in a
* platform-dependent header.
*/
typedef PREPACK struct {
A_UINT32 gpioreg_id; /* GPIO register ID */
A_UINT32 value; /* value to write */
} POSTPACK WMIX_GPIO_REGISTER_SET_CMD;
/* Get a GPIO register. For debug/exceptional cases. */
typedef PREPACK struct {
A_UINT32 gpioreg_id; /* GPIO register to read */
} POSTPACK WMIX_GPIO_REGISTER_GET_CMD;
/*
* Host acknowledges and re-arms GPIO interrupts. A single
* message should be used to acknowledge all interrupts that
* were delivered in an earlier WMIX_GPIO_INTR_EVENT message.
*/
typedef PREPACK struct {
A_UINT32 ack_mask; /* interrupts to acknowledge */
} POSTPACK WMIX_GPIO_INTR_ACK_CMD;
/*
* Target informs Host of GPIO interrupts that have ocurred since the
* last WMIX_GIPO_INTR_ACK_CMD was received. Additional information --
* the current GPIO input values is provided -- in order to support
* use of a GPIO interrupt as a Data Valid signal for other GPIO pins.
*/
typedef PREPACK struct {
A_UINT32 intr_mask; /* pending GPIO interrupts */
A_UINT32 input_values; /* recent GPIO input values */
} POSTPACK WMIX_GPIO_INTR_EVENT;
/*
* Target responds to Host's earlier WMIX_GPIO_INPUT_GET_CMDID request
* using a GPIO_DATA_EVENT with
* value set to the mask of GPIO pin inputs and
* reg_id set to GPIO_ID_NONE
*
*
* Target responds to Hosts's earlier WMIX_GPIO_REGISTER_GET_CMDID request
* using a GPIO_DATA_EVENT with
* value set to the value of the requested register and
* reg_id identifying the register (reflects the original request)
* NB: reg_id supports the future possibility of unsolicited
* WMIX_GPIO_DATA_EVENTs (for polling GPIO input), and it may
* simplify Host GPIO support.
*/
typedef PREPACK struct {
A_UINT32 value;
A_UINT32 reg_id;
} POSTPACK WMIX_GPIO_DATA_EVENT;
/*
* =============Error Detection support=================
*/
/*
* WMIX_HB_CHALLENGE_RESP_CMDID
* Heartbeat Challenge Response command
*/
typedef PREPACK struct {
A_UINT32 cookie;
A_UINT32 source;
} POSTPACK WMIX_HB_CHALLENGE_RESP_CMD;
/*
* WMIX_HB_CHALLENGE_RESP_EVENTID
* Heartbeat Challenge Response Event
*/
#define WMIX_HB_CHALLENGE_RESP_EVENT WMIX_HB_CHALLENGE_RESP_CMD
typedef PREPACK struct {
struct dbglog_config_s config;
} POSTPACK WMIX_DBGLOG_CFG_MODULE_CMD;
#ifndef ATH_TARGET
#include "athendpack.h"
#endif
#ifdef __cplusplus
}
#endif
#endif /* _WMIX_H_ */

View file

@ -0,0 +1,467 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "AR6Khwreg.h"
#include "targaddrs.h"
#include "a_osapi.h"
#include "hif.h"
#include "htc_api.h"
#include "bmi.h"
#include "bmi_msg.h"
#include "common_drv.h"
#include "a_debug.h"
#include "targaddrs.h"
#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
(((TargetType) == TARGET_TYPE_AR6001) ? \
AR6001_HOST_INTEREST_ITEM_ADDRESS(item) : \
AR6002_HOST_INTEREST_ITEM_ADDRESS(item))
/* Compile the 4BYTE version of the window register setup routine,
* This mitigates host interconnect issues with non-4byte aligned bus requests, some
* interconnects use bus adapters that impose strict limitations.
* Since diag window access is not intended for performance critical operations, the 4byte mode should
* be satisfactory even though it generates 4X the bus activity. */
#ifdef USE_4BYTE_REGISTER_ACCESS
/* set the window address register (using 4-byte register access ). */
A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
{
A_STATUS status;
A_UINT8 addrValue[4];
int i;
/* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
* last to initiate the access cycle */
for (i = 1; i <= 3; i++) {
/* fill the buffer with the address byte value we want to hit 4 times*/
addrValue[0] = ((A_UINT8 *)&Address)[i];
addrValue[1] = addrValue[0];
addrValue[2] = addrValue[0];
addrValue[3] = addrValue[0];
/* hit each byte of the register address with a 4-byte write operation to the same address,
* this is a harmless operation */
status = HIFReadWrite(hifDevice,
RegisterAddr+i,
addrValue,
4,
HIF_WR_SYNC_BYTE_FIX,
NULL);
if (status != A_OK) {
break;
}
}
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
RegisterAddr, Address));
return status;
}
/* write the address register again, this time write the whole 4-byte value.
* The effect here is that the LSB write causes the cycle to start, the extra
* 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */
status = HIFReadWrite(hifDevice,
RegisterAddr,
(A_UCHAR *)(&Address),
4,
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
RegisterAddr, Address));
return status;
}
return A_OK;
}
#else
/* set the window address register */
A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
{
A_STATUS status;
/* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
* last to initiate the access cycle */
status = HIFReadWrite(hifDevice,
RegisterAddr+1, /* write upper 3 bytes */
((A_UCHAR *)(&Address))+1,
sizeof(A_UINT32)-1,
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
RegisterAddr, Address));
return status;
}
/* write the LSB of the register, this initiates the operation */
status = HIFReadWrite(hifDevice,
RegisterAddr,
(A_UCHAR *)(&Address),
sizeof(A_UINT8),
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
RegisterAddr, Address));
return status;
}
return A_OK;
}
#endif
/*
* Read from the AR6000 through its diagnostic window.
* No cooperation from the Target is required for this.
*/
A_STATUS
ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
{
A_STATUS status;
/* set window register to start read cycle */
status = ar6000_SetAddressWindowRegister(hifDevice,
WINDOW_READ_ADDR_ADDRESS,
*address);
if (status != A_OK) {
return status;
}
/* read the data */
status = HIFReadWrite(hifDevice,
WINDOW_DATA_ADDRESS,
(A_UCHAR *)data,
sizeof(A_UINT32),
HIF_RD_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n"));
return status;
}
return status;
}
/*
* Write to the AR6000 through its diagnostic window.
* No cooperation from the Target is required for this.
*/
A_STATUS
ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
{
A_STATUS status;
/* set write data */
status = HIFReadWrite(hifDevice,
WINDOW_DATA_ADDRESS,
(A_UCHAR *)data,
sizeof(A_UINT32),
HIF_WR_SYNC_BYTE_INC,
NULL);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data));
return status;
}
/* set window register, which starts the write cycle */
return ar6000_SetAddressWindowRegister(hifDevice,
WINDOW_WRITE_ADDR_ADDRESS,
*address);
}
A_STATUS
ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
A_UCHAR *data, A_UINT32 length)
{
A_UINT32 count;
A_STATUS status = A_OK;
for (count = 0; count < length; count += 4, address += 4) {
if ((status = ar6000_ReadRegDiag(hifDevice, &address,
(A_UINT32 *)&data[count])) != A_OK)
{
break;
}
}
return status;
}
A_STATUS
ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
A_UCHAR *data, A_UINT32 length)
{
A_UINT32 count;
A_STATUS status = A_OK;
for (count = 0; count < length; count += 4, address += 4) {
if ((status = ar6000_WriteRegDiag(hifDevice, &address,
(A_UINT32 *)&data[count])) != A_OK)
{
break;
}
}
return status;
}
A_STATUS
ar6000_reset_device_skipflash(HIF_DEVICE *hifDevice)
{
int i;
struct forceROM_s {
A_UINT32 addr;
A_UINT32 data;
};
struct forceROM_s *ForceROM;
int szForceROM;
A_UINT32 instruction;
static struct forceROM_s ForceROM_REV2[] = {
/* NB: This works for old REV2 ROM (old). */
{0x00001ff0, 0x175b0027}, /* jump instruction at 0xa0001ff0 */
{0x00001ff4, 0x00000000}, /* nop instruction at 0xa0001ff4 */
{MC_REMAP_TARGET_ADDRESS, 0x00001ff0}, /* remap to 0xa0001ff0 */
{MC_REMAP_COMPARE_ADDRESS, 0x01000040},/* ...from 0xbfc00040 */
{MC_REMAP_SIZE_ADDRESS, 0x00000000}, /* ...1 cache line */
{MC_REMAP_VALID_ADDRESS, 0x00000001}, /* ...remap is valid */
{LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */
{RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK},
};
static struct forceROM_s ForceROM_NEW[] = {
/* NB: This works for AR6000 ROM REV3 and beyond. */
{LOCAL_SCRATCH_ADDRESS, AR6K_OPTION_IGNORE_FLASH},
{LOCAL_COUNT_ADDRESS+0x10, 0}, /* clear BMI credit counter */
{RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK},
};
/*
* Examine a semi-arbitrary instruction that's different
* in REV2 and other revisions.
* NB: If a Host port does not require simultaneous support
* for multiple revisions of Target ROM, this code can be elided.
*/
(void)ar6000_ReadDataDiag(hifDevice, 0x01000040,
(A_UCHAR *)&instruction, 4);
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("instruction=0x%x\n", instruction));
if (instruction == 0x3c1aa200) {
/* It's an old ROM */
ForceROM = ForceROM_REV2;
szForceROM = sizeof(ForceROM_REV2)/sizeof(*ForceROM);
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using OLD method\n"));
} else {
ForceROM = ForceROM_NEW;
szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM);
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Using NEW method\n"));
}
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Force Target to execute from ROM....\n"));
for (i = 0; i < szForceROM; i++)
{
if (ar6000_WriteRegDiag(hifDevice,
&ForceROM[i].addr,
&ForceROM[i].data) != A_OK)
{
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n"));
return A_ERROR;
}
}
msleep(50); /* delay to allow dragon to come to BMI phase */
return A_OK;
}
/* reset device */
A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
{
#if !defined(DWSIM)
A_STATUS status = A_OK;
A_UINT32 address;
A_UINT32 data;
do {
// address = RESET_CONTROL_ADDRESS;
data = RESET_CONTROL_COLD_RST_MASK;
/* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */
if (TargetType == TARGET_TYPE_AR6001) {
address = 0x0C000000;
} else {
if (TargetType == TARGET_TYPE_AR6002) {
address = 0x00004000;
} else {
A_ASSERT(0);
}
}
status = ar6000_WriteRegDiag(hifDevice, &address, &data);
if (A_FAILED(status)) {
break;
}
/*
* Read back the RESET CAUSE register to ensure that the cold reset
* went through.
*/
msleep(2000); /* 2 second delay to allow things to settle down */
// address = RESET_CAUSE_ADDRESS;
/* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */
if (TargetType == TARGET_TYPE_AR6001) {
address = 0x0C0000CC;
} else {
if (TargetType == TARGET_TYPE_AR6002) {
address = 0x000040C0;
} else {
A_ASSERT(0);
}
}
data = 0;
status = ar6000_ReadRegDiag(hifDevice, &address, &data);
if (A_FAILED(status)) {
break;
}
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data));
data &= RESET_CAUSE_LAST_MASK;
if (data != 2) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n"));
}
} while (FALSE);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n"));
}
#endif
return A_OK;
}
#define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR6001_regdump.h */
#define REG_DUMP_COUNT_AR6002 32 /* WORDs, derived from AR6002_regdump.h */
#if REG_DUMP_COUNT_AR6001 <= REG_DUMP_COUNT_AR6002
#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6002
#else
#define REGISTER_DUMP_LEN_MAX REG_DUMP_COUNT_AR6001
#endif
void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
{
A_UINT32 address;
A_UINT32 regDumpArea = 0;
A_STATUS status;
A_UINT32 regDumpValues[REGISTER_DUMP_LEN_MAX];
A_UINT32 regDumpCount = 0;
A_UINT32 i;
do {
/* the reg dump pointer is copied to the host interest area */
address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state);
if (TargetType == TARGET_TYPE_AR6001) {
/* for AR6001, this is a fixed location because the ptr is actually stuck in cache,
* this may be fixed in later firmware versions */
address = 0x18a0;
regDumpCount = REG_DUMP_COUNT_AR6001;
} else if (TargetType == TARGET_TYPE_AR6002) {
regDumpCount = REG_DUMP_COUNT_AR6002;
} else {
A_ASSERT(0);
}
/* read RAM location through diagnostic window */
status = ar6000_ReadRegDiag(hifDevice, &address, &regDumpArea);
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n"));
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea));
if (regDumpArea == 0) {
/* no reg dump */
break;
}
if (TargetType == TARGET_TYPE_AR6001) {
regDumpArea &= 0x0FFFFFFF; /* convert to physical address in target memory */
}
/* fetch register dump data */
status = ar6000_ReadDataDiag(hifDevice,
regDumpArea,
(A_UCHAR *)&regDumpValues[0],
regDumpCount * (sizeof(A_UINT32)));
if (A_FAILED(status)) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n"));
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n"));
for (i = 0; i < regDumpCount; i++) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i]));
}
} while (FALSE);
}

View file

@ -0,0 +1,346 @@
/*
*
* Copyright (c) 2004-2007 Atheros Communications Inc.
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "htc_api.h"
#include "common_drv.h"
/********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
#define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
#ifdef NO_VO_SERVICE
#define DATA_SVCS_USED 3
#else
#define DATA_SVCS_USED 4
#endif
static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
/* reduce an ep's credits back to a set limit */
static INLINE void ReduceCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
HTC_ENDPOINT_CREDIT_DIST *pEpDist,
int Limit)
{
int credits;
/* set the new limit */
pEpDist->TxCreditsAssigned = Limit;
if (pEpDist->TxCredits <= Limit) {
return;
}
/* figure out how much to take away */
credits = pEpDist->TxCredits - Limit;
/* take them away */
pEpDist->TxCredits -= credits;
pCredInfo->CurrentFreeCredits += credits;
}
/* give an endpoint some credits from the free credit pool */
#define GiveCredits(pCredInfo,pEpDist,credits) \
{ \
(pEpDist)->TxCredits += (credits); \
(pEpDist)->TxCreditsAssigned += (credits); \
(pCredInfo)->CurrentFreeCredits -= (credits); \
}
/* default credit init callback.
* This function is called in the context of HTCStart() to setup initial (application-specific)
* credit distributions */
static void ar6000_credit_init(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPList,
int TotalCredits)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
int count;
COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
pCredInfo->CurrentFreeCredits = TotalCredits;
pCredInfo->TotalAvailableCredits = TotalCredits;
pCurEpDist = pEPList;
/* run through the list and initialize */
while (pCurEpDist != NULL) {
/* set minimums for each endpoint */
pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
/* give control service some credits */
GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
/* control service is always marked active, it never goes inactive EVER */
SET_EP_ACTIVE(pCurEpDist);
} else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
/* this is the lowest priority data endpoint, save this off for easy access */
pCredInfo->pLowestPriEpDist = pCurEpDist;
}
/* Streams have to be created (explicit | implicit)for all kinds
* of traffic. BE endpoints are also inactive in the beginning.
* When BE traffic starts it creates implicit streams that
* redistributes credits.
*/
/* note, all other endpoints have minimums set but are initially given NO credits.
* Credits will be distributed as traffic activity demands */
pCurEpDist = pCurEpDist->pNext;
}
if (pCredInfo->CurrentFreeCredits <= 0) {
AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
A_ASSERT(FALSE);
return;
}
/* reset list */
pCurEpDist = pEPList;
/* now run through the list and set max operating credit limits for everyone */
while (pCurEpDist != NULL) {
if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
/* control service max is just 1 max message */
pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
} else {
/* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
* the same.
* We use a simple calculation here, we take the remaining credits and
* determine how many max messages this can cover and then set each endpoint's
* normal value equal to half this amount.
* */
count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
count = count >> 1;
count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
/* set normal */
pCurEpDist->TxCreditsNorm = count;
}
pCurEpDist = pCurEpDist->pNext;
}
}
/* default credit distribution callback
* This callback is invoked whenever endpoints require credit distributions.
* A lock is held while this function is invoked, this function shall NOT block.
* The pEPDistList is a list of distribution structures in prioritized order as
* defined by the call to the HTCSetCreditDistribution() api.
*
*/
static void ar6000_credit_distribute(void *Context,
HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
HTC_CREDIT_DIST_REASON Reason)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
switch (Reason) {
case HTC_CREDIT_DIST_SEND_COMPLETE :
pCurEpDist = pEPDistList;
/* we are given the start of the endpoint distribution list.
* There may be one or more endpoints to service.
* Run through the list and distribute credits */
while (pCurEpDist != NULL) {
if (pCurEpDist->TxCreditsToDist > 0) {
/* return the credits back to the endpoint */
pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
/* always zero out when we are done */
pCurEpDist->TxCreditsToDist = 0;
if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
/* reduce to the assigned limit, previous credit reductions
* could have caused the limit to change */
ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
}
if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
/* oversubscribed endpoints need to reduce back to normal */
ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
}
}
pCurEpDist = pCurEpDist->pNext;
}
A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
break;
case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
RedistributeCredits(pCredInfo,pEPDistList);
break;
case HTC_CREDIT_DIST_SEEK_CREDITS :
SeekCredits(pCredInfo,pEPDistList);
break;
case HTC_DUMP_CREDIT_STATE :
AR_DEBUG_PRINTF(ATH_LOG_INF, ("Credit Distribution, total : %d, free : %d\n",
pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
break;
default:
break;
}
}
/* redistribute credits based on activity change */
static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
HTC_ENDPOINT_CREDIT_DIST *pEPDistList)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist = pEPDistList;
/* walk through the list and remove credits from inactive endpoints */
while (pCurEpDist != NULL) {
if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
if (!IS_EP_ACTIVE(pCurEpDist)) {
/* EP is inactive, reduce credits back to zero */
ReduceCredits(pCredInfo, pCurEpDist, 0);
}
}
/* NOTE in the active case, we do not need to do anything further,
* when an EP goes active and needs credits, HTC will call into
* our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
pCurEpDist = pCurEpDist->pNext;
}
A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
}
/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
HTC_ENDPOINT_CREDIT_DIST *pEPDist)
{
HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
int credits = 0;
int need;
do {
if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
/* we never oversubscribe on the control service, this is not
* a high performance path and the target never holds onto control
* credits for too long */
break;
}
/* for all other services, we follow a simple algorithm of
* 1. checking the free pool for credits
* 2. checking lower priority endpoints for credits to take */
if (pCredInfo->CurrentFreeCredits >= 2 * pEPDist->TxCreditsSeek) {
/* try to give more credits than it needs */
credits = 2 * pEPDist->TxCreditsSeek;
} else {
/* give what we can */
credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
}
if (credits >= pEPDist->TxCreditsSeek) {
/* we found some to fullfill the seek request */
break;
}
/* we don't have enough in the free pool, try taking away from lower priority services
*
* The rule for taking away credits:
* 1. Only take from lower priority endpoints
* 2. Only take what is allocated above the minimum (never starve an endpoint completely)
* 3. Only take what you need.
*
* */
/* starting at the lowest priority */
pCurEpDist = pCredInfo->pLowestPriEpDist;
/* work backwards until we hit the endpoint again */
while (pCurEpDist != pEPDist) {
/* calculate how many we need so far */
need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
if ((pCurEpDist->TxCreditsAssigned - need) > pCurEpDist->TxCreditsMin) {
/* the current one has been allocated more than it's minimum and it
* has enough credits assigned above it's minimum to fullfill our need
* try to take away just enough to fullfill our need */
ReduceCredits(pCredInfo,
pCurEpDist,
pCurEpDist->TxCreditsAssigned - need);
if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
/* we have enough */
break;
}
}
pCurEpDist = pCurEpDist->pPrev;
}
/* return what we can get */
credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
} while (FALSE);
/* did we find some credits? */
if (credits) {
/* give what we can */
GiveCredits(pCredInfo, pEPDist, credits);
}
}
/* initialize and setup credit distribution */
A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo)
{
HTC_SERVICE_ID servicepriority[5];
A_MEMZERO(pCredInfo,sizeof(COMMON_CREDIT_STATE_INFO));
servicepriority[0] = WMI_CONTROL_SVC; /* highest */
servicepriority[1] = WMI_DATA_VO_SVC;
servicepriority[2] = WMI_DATA_VI_SVC;
servicepriority[3] = WMI_DATA_BE_SVC;
servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
/* set callbacks and priority list */
HTCSetCreditDistribution(HTCHandle,
pCredInfo,
ar6000_credit_distribute,
ar6000_credit_init,
servicepriority,
5);
return A_OK;
}

View file

@ -0,0 +1,371 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
* Copyright (c) 2004-2005 Atheros Communications
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/wlan/src/wlan_node.c#1 $
*/
/*
* IEEE 802.11 node handling support.
*/
#include <a_config.h>
#include <athdefs.h>
#include <a_types.h>
#include <a_osapi.h>
#include <a_debug.h>
#include <ieee80211.h>
#include <wlan_api.h>
#include <ieee80211_node.h>
#include <htc_api.h>
#include <wmi.h>
#include <wmi_api.h>
static void wlan_node_timeout(A_ATH_TIMER arg);
static bss_t * _ieee80211_find_node(struct ieee80211_node_table *nt,
const A_UINT8 *macaddr);
bss_t *
wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
{
bss_t *ni;
ni = A_MALLOC_NOWAIT(sizeof(bss_t));
if (ni != NULL) {
ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
if (ni->ni_buf == NULL) {
A_FREE(ni);
ni = NULL;
return ni;
}
} else {
return ni;
}
/* Make sure our lists are clean */
ni->ni_list_next = NULL;
ni->ni_list_prev = NULL;
ni->ni_hash_next = NULL;
ni->ni_hash_prev = NULL;
//
// ni_scangen never initialized before and during suspend/resume of winmobile, customer (LG/SEMCO) identified
// that some junk has been stored in this, due to this scan list didn't properly updated
//
ni->ni_scangen = 0;
return ni;
}
void
wlan_node_free(bss_t *ni)
{
if (ni->ni_buf != NULL) {
A_FREE(ni->ni_buf);
}
A_FREE(ni);
}
void
wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
const A_UINT8 *macaddr)
{
int hash;
A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
hash = IEEE80211_NODE_HASH(macaddr);
ieee80211_node_initref(ni); /* mark referenced */
ni->ni_tstamp = A_GET_MS(WLAN_NODE_INACT_TIMEOUT_MSEC);
IEEE80211_NODE_LOCK_BH(nt);
/* Insert at the end of the node list */
ni->ni_list_next = NULL;
ni->ni_list_prev = nt->nt_node_last;
if(nt->nt_node_last != NULL)
{
nt->nt_node_last->ni_list_next = ni;
}
nt->nt_node_last = ni;
if(nt->nt_node_first == NULL)
{
nt->nt_node_first = ni;
}
/* Insert into the hash list i.e. the bucket */
if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
{
nt->nt_hash[hash]->ni_hash_prev = ni;
}
ni->ni_hash_prev = NULL;
nt->nt_hash[hash] = ni;
if (!nt->isTimerArmed) {
A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
nt->isTimerArmed = TRUE;
}
IEEE80211_NODE_UNLOCK_BH(nt);
}
static bss_t *
_ieee80211_find_node(struct ieee80211_node_table *nt,
const A_UINT8 *macaddr)
{
bss_t *ni;
int hash;
IEEE80211_NODE_LOCK_ASSERT(nt);
hash = IEEE80211_NODE_HASH(macaddr);
for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
ieee80211_node_incref(ni); /* mark referenced */
return ni;
}
}
return NULL;
}
bss_t *
wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr)
{
bss_t *ni;
IEEE80211_NODE_LOCK(nt);
ni = _ieee80211_find_node(nt, macaddr);
IEEE80211_NODE_UNLOCK(nt);
return ni;
}
/*
* Reclaim a node. If this is the last reference count then
* do the normal free work. Otherwise remove it from the node
* table and mark it gone by clearing the back-reference.
*/
void
wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
{
IEEE80211_NODE_LOCK(nt);
if(ni->ni_list_prev == NULL)
{
/* First in list so fix the list head */
nt->nt_node_first = ni->ni_list_next;
}
else
{
ni->ni_list_prev->ni_list_next = ni->ni_list_next;
}
if(ni->ni_list_next == NULL)
{
/* Last in list so fix list tail */
nt->nt_node_last = ni->ni_list_prev;
}
else
{
ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
}
if(ni->ni_hash_prev == NULL)
{
/* First in list so fix the list head */
int hash;
hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
nt->nt_hash[hash] = ni->ni_hash_next;
}
else
{
ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
}
if(ni->ni_hash_next != NULL)
{
ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
}
wlan_node_free(ni);
IEEE80211_NODE_UNLOCK(nt);
}
static void
wlan_node_dec_free(bss_t *ni)
{
if (ieee80211_node_dectestref(ni)) {
wlan_node_free(ni);
}
}
void
wlan_free_allnodes(struct ieee80211_node_table *nt)
{
bss_t *ni;
while ((ni = nt->nt_node_first) != NULL) {
wlan_node_reclaim(nt, ni);
}
}
void
wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
void *arg)
{
bss_t *ni;
A_UINT32 gen;
gen = ++nt->nt_scangen;
IEEE80211_NODE_LOCK(nt);
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
if (ni->ni_scangen != gen) {
ni->ni_scangen = gen;
(void) ieee80211_node_incref(ni);
(*f)(arg, ni);
wlan_node_dec_free(ni);
}
}
IEEE80211_NODE_UNLOCK(nt);
}
/*
* Node table support.
*/
void
wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
{
int i;
AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%x\n", (A_UINT32)nt));
IEEE80211_NODE_LOCK_INIT(nt);
nt->nt_node_first = nt->nt_node_last = NULL;
for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
{
nt->nt_hash[i] = NULL;
}
A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
nt->isTimerArmed = FALSE;
nt->nt_wmip = wmip;
}
static void
wlan_node_timeout(A_ATH_TIMER arg)
{
struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg;
bss_t *bss, *nextBss;
A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE;
wmi_get_current_bssid(nt->nt_wmip, myBssid);
bss = nt->nt_node_first;
while (bss != NULL)
{
nextBss = bss->ni_list_next;
if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
{
if (bss->ni_tstamp <= A_GET_MS(0))
{
/*
* free up all but the current bss - if set
*/
wlan_node_reclaim(nt, bss);
}
else
{
/*
* Re-arm timer, only when we have a bss other than
* current bss AND it is not aged-out.
*/
reArmTimer = TRUE;
}
}
bss = nextBss;
}
if(reArmTimer)
A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
nt->isTimerArmed = reArmTimer;
}
void
wlan_node_table_cleanup(struct ieee80211_node_table *nt)
{
A_UNTIMEOUT(&nt->nt_inact_timer);
A_DELETE_TIMER(&nt->nt_inact_timer);
wlan_free_allnodes(nt);
IEEE80211_NODE_LOCK_DESTROY(nt);
}
bss_t *
wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
A_UINT32 ssidLength, A_BOOL bIsWPA2)
{
bss_t *ni = NULL;
A_UCHAR *pIESsid = NULL;
IEEE80211_NODE_LOCK (nt);
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
pIESsid = ni->ni_cie.ie_ssid;
if (pIESsid[1] <= 32) {
// Step 1 : Check SSID
if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
// Step 2 : if SSID matches, check WPA or WPA2
if (TRUE == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) {
ieee80211_node_incref (ni); /* mark referenced */
IEEE80211_NODE_UNLOCK (nt);
return ni;
}
if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
ieee80211_node_incref(ni); /* mark referenced */
IEEE80211_NODE_UNLOCK (nt);
return ni;
}
}
}
}
IEEE80211_NODE_UNLOCK (nt);
return NULL;
}
void
wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
{
IEEE80211_NODE_LOCK (nt);
wlan_node_dec_free (ni);
IEEE80211_NODE_UNLOCK (nt);
}

View file

@ -0,0 +1,192 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* IEEE 802.11 input handling.
*/
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include <wmi.h>
#include <ieee80211.h>
#include <wlan_api.h>
#define IEEE80211_VERIFY_LENGTH(_len, _minlen) do { \
if ((_len) < (_minlen)) { \
return A_EINVAL; \
} \
} while (0)
#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do { \
if ((__elem) == NULL) { \
return A_EINVAL; \
} \
if ((__elem)[1] > (__maxlen)) { \
return A_EINVAL; \
} \
} while (0)
/* unaligned little endian access */
#define LE_READ_2(p) \
((A_UINT16) \
((((A_UINT8 *)(p))[0] ) | (((A_UINT8 *)(p))[1] << 8)))
#define LE_READ_4(p) \
((A_UINT32) \
((((A_UINT8 *)(p))[0] ) | (((A_UINT8 *)(p))[1] << 8) | \
(((A_UINT8 *)(p))[2] << 16) | (((A_UINT8 *)(p))[3] << 24)))
static int __inline
iswpaoui(const A_UINT8 *frm)
{
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
}
static int __inline
iswmmoui(const A_UINT8 *frm)
{
return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
}
static int __inline
iswmmparam(const A_UINT8 *frm)
{
return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
}
static int __inline
iswmminfo(const A_UINT8 *frm)
{
return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
}
static int __inline
isatherosoui(const A_UINT8 *frm)
{
return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
}
static int __inline
iswscoui(const A_UINT8 *frm)
{
return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
}
A_STATUS
wlan_parse_beacon(A_UINT8 *buf, int framelen, struct ieee80211_common_ie *cie)
{
A_UINT8 *frm, *efrm;
frm = buf;
efrm = (A_UINT8 *) (frm + framelen);
/*
* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
* [tlv] supported rates
* [tlv] country information
* [tlv] parameter set (FH/DS)
* [tlv] erp information
* [tlv] extended supported rates
* [tlv] WMM
* [tlv] WPA or RSN
* [tlv] Atheros Advanced Capabilities
*/
IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
A_MEMZERO(cie, sizeof(*cie));
cie->ie_tstamp = frm; frm += 8;
cie->ie_beaconInt = A_LE2CPU16(*(A_UINT16 *)frm); frm += 2;
cie->ie_capInfo = A_LE2CPU16(*(A_UINT16 *)frm); frm += 2;
cie->ie_chan = 0;
while (frm < efrm) {
switch (*frm) {
case IEEE80211_ELEMID_SSID:
cie->ie_ssid = frm;
break;
case IEEE80211_ELEMID_RATES:
cie->ie_rates = frm;
break;
case IEEE80211_ELEMID_COUNTRY:
cie->ie_country = frm;
break;
case IEEE80211_ELEMID_FHPARMS:
break;
case IEEE80211_ELEMID_DSPARMS:
cie->ie_chan = frm[2];
break;
case IEEE80211_ELEMID_TIM:
cie->ie_tim = frm;
break;
case IEEE80211_ELEMID_IBSSPARMS:
break;
case IEEE80211_ELEMID_XRATES:
cie->ie_xrates = frm;
break;
case IEEE80211_ELEMID_ERP:
if (frm[1] != 1) {
//A_PRINTF("Discarding ERP Element - Bad Len\n");
return A_EINVAL;
}
cie->ie_erp = frm[2];
break;
case IEEE80211_ELEMID_RSN:
cie->ie_rsn = frm;
break;
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(frm)) {
cie->ie_wpa = frm;
} else if (iswmmoui(frm)) {
cie->ie_wmm = frm;
} else if (isatherosoui(frm)) {
cie->ie_ath = frm;
} else if(iswscoui(frm)) {
cie->ie_wsc = frm;
}
break;
default:
break;
}
frm += frm[1] + 2;
}
IEEE80211_VERIFY_ELEMENT(cie->ie_rates, IEEE80211_RATE_MAXSIZE);
IEEE80211_VERIFY_ELEMENT(cie->ie_ssid, IEEE80211_NWID_LEN);
return A_OK;
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2004-2005 Atheros Communications Inc.
* All rights reserved.
*
* This module implements frequently used wlan utilies
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/wlan/src/wlan_utils.c#1 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#include <a_config.h>
#include <athdefs.h>
#include <a_types.h>
#include <a_osapi.h>
/*
* converts ieee channel number to frequency
*/
A_UINT16
wlan_ieee2freq(int chan)
{
if (chan == 14) {
return 2484;
}
if (chan < 14) { /* 0-13 */
return (2407 + (chan*5));
}
if (chan < 27) { /* 15-26 */
return (2512 + ((chan-15)*20));
}
return (5000 + (chan*5));
}
/*
* Converts MHz frequency to IEEE channel number.
*/
A_UINT32
wlan_freq2ieee(A_UINT16 freq)
{
if (freq == 2484)
return 14;
if (freq < 2484)
return (freq - 2407) / 5;
if (freq < 5000)
return 15 + ((freq - 2512) / 20);
return (freq - 5000) / 5;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
#ifndef _WMI_HOST_H_
#define _WMI_HOST_H_
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
* All rights reserved.
*
* This file contains local definitios for the wmi host module.
*
* $Id: //depot/sw/releases/olca2.0-GPL/host/wmi/wmi_host.h#1 $
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
*
*/
#ifdef __cplusplus
extern "C" {
#endif
struct wmi_stats {
A_UINT32 cmd_len_err;
A_UINT32 cmd_id_err;
};
struct wmi_t {
A_BOOL wmi_ready;
A_BOOL wmi_numQoSStream;
A_UINT8 wmi_wmiStream2AcMapping[WMI_PRI_MAX_COUNT];
WMI_PRI_STREAM_ID wmi_ac2WmiStreamMapping[WMM_NUM_AC];
A_UINT16 wmi_streamExistsForAC[WMM_NUM_AC];
A_UINT8 wmi_fatPipeExists;
void *wmi_devt;
struct wmi_stats wmi_stats;
struct ieee80211_node_table wmi_scan_table;
A_UINT8 wmi_bssid[ATH_MAC_LEN];
A_UINT8 wmi_powerMode;
A_UINT8 wmi_phyMode;
A_UINT8 wmi_keepaliveInterval;
A_MUTEX_T wmi_lock;
};
#define WMI_INIT_WMISTREAM_AC_MAP(w) \
{ (w)->wmi_wmiStream2AcMapping[WMI_BEST_EFFORT_PRI] = WMM_AC_BE; \
(w)->wmi_wmiStream2AcMapping[WMI_LOW_PRI] = WMM_AC_BK; \
(w)->wmi_wmiStream2AcMapping[WMI_HIGH_PRI] = WMM_AC_VI; \
(w)->wmi_wmiStream2AcMapping[WMI_HIGHEST_PRI] = WMM_AC_VO; \
(w)->wmi_ac2WmiStreamMapping[WMM_AC_BE] = WMI_BEST_EFFORT_PRI; \
(w)->wmi_ac2WmiStreamMapping[WMM_AC_BK] = WMI_LOW_PRI; \
(w)->wmi_ac2WmiStreamMapping[WMM_AC_VI] = WMI_HIGH_PRI; \
(w)->wmi_ac2WmiStreamMapping[WMM_AC_VO] = WMI_HIGHEST_PRI; }
#define WMI_WMISTREAM_ACCESSCATEGORY(w,s) (w)->wmi_wmiStream2AcMapping[s]
#define WMI_ACCESSCATEGORY_WMISTREAM(w,ac) (w)->wmi_ac2WmiStreamMapping[ac]
#define LOCK_WMI(w) A_MUTEX_LOCK(&(w)->wmi_lock);
#define UNLOCK_WMI(w) A_MUTEX_UNLOCK(&(w)->wmi_lock);
#ifdef __cplusplus
}
#endif
#endif /* _WMI_HOST_H_ */

View file

@ -0,0 +1,442 @@
/*
* Keyboard driver for Openmoko Freerunner GSM phone
*
* (C) 2006-2007 by Openmoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
* All rights reserved.
*
* inspired by corkgbd.c by Richard Purdie
*
* 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/delay.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <mach/gpio.h>
#include <asm/mach-types.h>
#ifdef CONFIG_PM
extern int global_inside_suspend;
#else
#define global_inside_suspend 0
#endif
struct gta02kbd {
struct platform_device *pdev;
struct input_dev *input;
struct device *cdev;
struct work_struct work;
int aux_state;
int work_in_progress;
int hp_irq_count_in_work;
int hp_irq_count;
int jack_irq;
};
static struct class *gta02kbd_switch_class;
enum keys {
GTA02_KEY_AUX,
GTA02_KEY_HOLD,
GTA02_KEY_JACK,
};
struct gta02kbd_key {
const char * name;
irqreturn_t (*isr)(int irq, void *dev_id);
int irq;
int input_key;
};
static irqreturn_t gta02kbd_aux_irq(int irq, void *dev_id);
static irqreturn_t gta02kbd_headphone_irq(int irq, void *dev_id);
static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id);
static struct gta02kbd_key keys[] = {
[GTA02_KEY_AUX] = {
.name = "GTA02 AUX button",
.isr = gta02kbd_aux_irq,
.input_key = KEY_PHONE,
},
[GTA02_KEY_HOLD] = {
.name = "GTA02 HOLD button",
.isr = gta02kbd_default_key_irq,
.input_key = KEY_PAUSE,
},
[GTA02_KEY_JACK] = {
.name = "GTA02 Headphone jack",
.isr = gta02kbd_headphone_irq,
},
};
/* This timer section filters AUX button IRQ bouncing */
static void aux_key_timer_f(unsigned long data);
static struct timer_list aux_key_timer =
TIMER_INITIALIZER(aux_key_timer_f, 0, 0);
#define AUX_TIMER_TIMEOUT (HZ >> 7)
#define AUX_TIMER_ALLOWED_NOOP 2
#define AUX_TIMER_CONSECUTIVE_EVENTS 5
struct gta02kbd *timer_kbd;
static void aux_key_timer_f(unsigned long data)
{
static int noop_counter;
static int last_key = -1;
static int last_count;
int key_pressed;
key_pressed =
gpio_get_value(timer_kbd->pdev->resource[GTA02_KEY_AUX].start);
if (likely(key_pressed == last_key))
last_count++;
else {
last_count = 1;
last_key = key_pressed;
}
if (unlikely(last_count >= AUX_TIMER_CONSECUTIVE_EVENTS)) {
if (timer_kbd->aux_state != last_key) {
input_report_key(timer_kbd->input, KEY_PHONE, last_key);
input_sync(timer_kbd->input);
timer_kbd->aux_state = last_key;
noop_counter = 0;
}
last_count = 0;
if (unlikely(++noop_counter > AUX_TIMER_ALLOWED_NOOP)) {
noop_counter = 0;
return;
}
}
mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
}
static irqreturn_t gta02kbd_aux_irq(int irq, void *dev)
{
mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
return IRQ_HANDLED;
}
static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id)
{
struct gta02kbd *kbd = dev_id;
int n;
for (n = 0; n < ARRAY_SIZE(keys); n++) {
if (irq != keys[n].irq)
continue;
input_report_key(kbd->input, keys[n].input_key,
gpio_get_value(kbd->pdev->resource[n].start));
input_sync(kbd->input);
}
return IRQ_HANDLED;
}
static const char *event_array_jack[2][4] = {
[0] = {
"SWITCH_NAME=headset",
"SWITCH_STATE=0",
"EVENT=remove",
NULL
},
[1] = {
"SWITCH_NAME=headset",
"SWITCH_STATE=1",
"EVENT=insert",
NULL
},
};
static void gta02kbd_jack_event(struct device *dev, int num)
{
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, (char **)event_array_jack[!!num]);
}
static void gta02kbd_debounce_jack(struct work_struct *work)
{
struct gta02kbd *kbd = container_of(work, struct gta02kbd, work);
unsigned long flags;
int loop = 0;
int level;
do {
/*
* we wait out any multiple interrupt
* stuttering in 100ms lumps
*/
do {
kbd->hp_irq_count_in_work = kbd->hp_irq_count;
msleep(100);
} while (kbd->hp_irq_count != kbd->hp_irq_count_in_work);
/*
* no new interrupts on jack for 100ms...
* ok we will report it
*/
level = gpio_get_value(kbd->pdev->resource[GTA02_KEY_JACK].start);
input_report_switch(kbd->input, SW_HEADPHONE_INSERT, level);
input_sync(kbd->input);
gta02kbd_jack_event(kbd->cdev, level);
/*
* we go around the outer loop again if we detect that more
* interrupts came while we are servicing here. But we have
* to sequence it carefully with interrupts off
*/
local_save_flags(flags);
/* no interrupts during this work means we can exit the work */
loop = !!(kbd->hp_irq_count != kbd->hp_irq_count_in_work);
if (!loop)
kbd->work_in_progress = 0;
local_irq_restore(flags);
/*
* interrupt that comes here will either queue a new work action
* since work_in_progress is cleared now, or be dealt with
* when we loop.
*/
} while (loop);
}
static irqreturn_t gta02kbd_headphone_irq(int irq, void *dev_id)
{
struct gta02kbd *gta02kbd_data = dev_id;
/*
* this interrupt is prone to bouncing and userspace doesn't like
* to have to deal with that kind of thing. So we do not accept
* that a jack interrupt is equal to a jack event. Instead we fire
* some work on the first interrupt, and it hangs about in 100ms units
* until no more interrupts come. Then it accepts the state it finds
* for jack insert and reports it once
*/
gta02kbd_data->hp_irq_count++;
/*
* the first interrupt we see for a while, we fire the work item
* and record the interrupt count when we did that. If more interrupts
* come in the meanwhile, we can tell by the difference in that
* stored count and hp_irq_count which increments every interrupt
*/
if (!gta02kbd_data->work_in_progress) {
gta02kbd_data->jack_irq = irq;
gta02kbd_data->hp_irq_count_in_work =
gta02kbd_data->hp_irq_count;
if (!schedule_work(&gta02kbd_data->work))
printk(KERN_ERR
"Unable to schedule headphone debounce\n");
else
gta02kbd_data->work_in_progress = 1;
}
return IRQ_HANDLED;
}
#ifdef CONFIG_PM
static int gta02kbd_suspend(struct platform_device *dev, pm_message_t state)
{
disable_irq(keys[GTA02_KEY_AUX].irq);
del_timer_sync(&aux_key_timer);
return 0;
}
static int gta02kbd_resume(struct platform_device *dev)
{
enable_irq(keys[GTA02_KEY_AUX].irq);
return 0;
}
#else
#define gta02kbd_suspend NULL
#define gta02kbd_resume NULL
#endif
static ssize_t gta02kbd_switch_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", "gta02 Headset Jack");
}
static ssize_t gta02kbd_switch_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gta02kbd *kbd = dev_get_drvdata(dev);
return sprintf(buf, "%d\n",
gpio_get_value(kbd->pdev->resource[GTA02_KEY_JACK].start));
}
static DEVICE_ATTR(name, S_IRUGO , gta02kbd_switch_name_show, NULL);
static DEVICE_ATTR(state, S_IRUGO , gta02kbd_switch_state_show, NULL);
static int gta02kbd_probe(struct platform_device *pdev)
{
struct gta02kbd *gta02kbd;
struct input_dev *input_dev;
int rc;
int irq;
int n;
gta02kbd = kzalloc(sizeof(struct gta02kbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gta02kbd || !input_dev) {
kfree(gta02kbd);
input_free_device(input_dev);
return -ENOMEM;
}
gta02kbd->pdev = pdev;
timer_kbd = gta02kbd;
if (pdev->resource[0].flags != 0)
return -EINVAL;
platform_set_drvdata(pdev, gta02kbd);
gta02kbd->input = input_dev;
INIT_WORK(&gta02kbd->work, gta02kbd_debounce_jack);
input_dev->name = "GTA02 Buttons";
input_dev->phys = "gta02kbd/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SW);
set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
set_bit(KEY_PHONE, input_dev->keybit);
set_bit(KEY_PAUSE, input_dev->keybit);
rc = input_register_device(gta02kbd->input);
if (rc)
goto out_register;
gta02kbd->cdev = device_create(gta02kbd_switch_class,
&pdev->dev, 0, gta02kbd, "headset");
if (unlikely(IS_ERR(gta02kbd->cdev))) {
rc = PTR_ERR(gta02kbd->cdev);
goto out_device_create;
}
rc = device_create_file(gta02kbd->cdev, &dev_attr_name);
if(rc)
goto out_device_create_file;
rc = device_create_file(gta02kbd->cdev, &dev_attr_state);
if(rc)
goto out_device_create_file;
/* register GPIO IRQs */
for(n = 0; n < min(pdev->num_resources, ARRAY_SIZE(keys)); n++) {
if (!pdev->resource[0].start)
continue;
irq = gpio_to_irq(pdev->resource[n].start);
if (irq < 0)
continue;
if (request_irq(irq, keys[n].isr, IRQF_DISABLED |
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
keys[n].name, gta02kbd)) {
dev_err(&pdev->dev, "Can't get IRQ %u\n", irq);
/* unwind any irq registrations and fail */
while (n > 0) {
n--;
free_irq(gpio_to_irq(pdev->resource[n].start),
gta02kbd);
}
goto out_device_create_file;
}
keys[n].irq = irq;
}
enable_irq_wake(keys[GTA02_KEY_JACK].irq);
return 0;
out_device_create_file:
device_unregister(gta02kbd->cdev);
out_device_create:
input_unregister_device(gta02kbd->input);
out_register:
input_free_device(gta02kbd->input);
platform_set_drvdata(pdev, NULL);
kfree(gta02kbd);
return -ENODEV;
}
static int gta02kbd_remove(struct platform_device *pdev)
{
struct gta02kbd *gta02kbd = platform_get_drvdata(pdev);
free_irq(gpio_to_irq(pdev->resource[2].start), gta02kbd);
free_irq(gpio_to_irq(pdev->resource[1].start), gta02kbd);
free_irq(gpio_to_irq(pdev->resource[0].start), gta02kbd);
device_unregister(gta02kbd->cdev);
input_unregister_device(gta02kbd->input);
input_free_device(gta02kbd->input);
platform_set_drvdata(pdev, NULL);
kfree(gta02kbd);
return 0;
}
static struct platform_driver gta02kbd_driver = {
.probe = gta02kbd_probe,
.remove = gta02kbd_remove,
.suspend = gta02kbd_suspend,
.resume = gta02kbd_resume,
.driver = {
.name = "gta02-button",
},
};
static int __devinit gta02kbd_init(void)
{
gta02kbd_switch_class = class_create(THIS_MODULE, "switch");
if (IS_ERR(gta02kbd_switch_class))
return PTR_ERR(gta02kbd_switch_class);
return platform_driver_register(&gta02kbd_driver);
}
static void __exit gta02kbd_exit(void)
{
platform_driver_unregister(&gta02kbd_driver);
class_destroy(gta02kbd_switch_class);
}
module_init(gta02kbd_init);
module_exit(gta02kbd_exit);
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
MODULE_DESCRIPTION("Openmoko Freerunner buttons input driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,957 @@
/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
*
* Copyright (C) 2007-2008 by Openmoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
* converted to private bitbang by:
* Andy Green <andy@openmoko.com>
* ability to set acceleration threshold added by:
* Simon Kagstrom <simon.kagstrom@gmail.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* TODO
* * statistics for overflow events
* * configuration interface (sysfs) for
* * enable/disable x/y/z axis data ready
* * enable/disable resume from freee fall / click
* * free fall / click parameters
* * high pass filter parameters
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/lis302dl.h>
/* Utility functions */
static u8 __reg_read(struct lis302dl_info *lis, u8 reg)
{
struct spi_message msg;
struct spi_transfer t;
u8 data[2] = {0xc0 | reg};
int rc;
spi_message_init(&msg);
memset(&t, 0, sizeof t);
t.len = 2;
spi_message_add_tail(&t, &msg);
t.tx_buf = &data[0];
t.rx_buf = &data[0];
/* Should complete without blocking */
rc = spi_non_blocking_transfer(lis->spi, &msg);
if (rc < 0) {
dev_err(lis->dev, "Error reading register\n");
return rc;
}
return data[1];
}
static void __reg_write(struct lis302dl_info *lis, u8 reg, u8 val)
{
struct spi_message msg;
struct spi_transfer t;
u8 data[2] = {reg, val};
spi_message_init(&msg);
memset(&t, 0, sizeof t);
t.len = 2;
spi_message_add_tail(&t, &msg);
t.tx_buf = &data[0];
t.rx_buf = &data[0];
/* Completes without blocking */
if (spi_non_blocking_transfer(lis->spi, &msg) < 0)
dev_err(lis->dev, "Error writing register\n");
}
static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
u8 val)
{
u_int8_t tmp;
val &= mask;
tmp = __reg_read(lis, reg);
tmp &= ~mask;
tmp |= val;
__reg_write(lis, reg, tmp);
}
static int __ms_to_duration(struct lis302dl_info *lis, int ms)
{
/* If we have 400 ms sampling rate, the stepping is 2.5 ms,
* on 100 ms the stepping is 10ms */
if (lis->flags & LIS302DL_F_DR)
return min((ms * 10) / 25, 637);
return min(ms / 10, 2550);
}
static int __duration_to_ms(struct lis302dl_info *lis, int duration)
{
if (lis->flags & LIS302DL_F_DR)
return (duration * 25) / 10;
return duration * 10;
}
static u8 __mg_to_threshold(struct lis302dl_info *lis, int mg)
{
/* If FS is set each bit is 71mg, otherwise 18mg. The THS register
* has 7 bits for the threshold value */
if (lis->flags & LIS302DL_F_FS)
return min(mg / 71, 127);
return min(mg / 18, 127);
}
static int __threshold_to_mg(struct lis302dl_info *lis, u8 threshold)
{
if (lis->flags & LIS302DL_F_FS)
return threshold * 71;
return threshold * 18;
}
/* interrupt handling related */
enum lis302dl_intmode {
LIS302DL_INTMODE_GND = 0x00,
LIS302DL_INTMODE_FF_WU_1 = 0x01,
LIS302DL_INTMODE_FF_WU_2 = 0x02,
LIS302DL_INTMODE_FF_WU_12 = 0x03,
LIS302DL_INTMODE_DATA_READY = 0x04,
LIS302DL_INTMODE_CLICK = 0x07,
};
static void __lis302dl_int_mode(struct device *dev, int int_pin,
enum lis302dl_intmode mode)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
switch (int_pin) {
case 1:
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
break;
case 2:
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
break;
default:
BUG();
}
}
static void __enable_wakeup(struct lis302dl_info *lis)
{
__reg_write(lis, LIS302DL_REG_CTRL1, 0);
/* First zero to get to a known state */
__reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE |
LIS302DL_FFWUCFG_LIR);
__reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
__mg_to_threshold(lis, lis->wakeup.threshold));
__reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
__ms_to_duration(lis, lis->wakeup.duration));
/* Route the interrupt for wakeup */
__lis302dl_int_mode(lis->dev, 1,
LIS302DL_INTMODE_FF_WU_1);
__reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
__reg_read(lis, LIS302DL_REG_OUT_X);
__reg_read(lis, LIS302DL_REG_OUT_Y);
__reg_read(lis, LIS302DL_REG_OUT_Z);
__reg_read(lis, LIS302DL_REG_STATUS);
__reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
__reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
__reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
}
static void __enable_data_collection(struct lis302dl_info *lis)
{
u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
/* make sure we're powered up and generate data ready */
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
/* If the threshold is zero, let the device generated an interrupt
* on each datum */
if (lis->threshold == 0) {
__reg_write(lis, LIS302DL_REG_CTRL2, 0);
__lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
__lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
} else {
__reg_write(lis, LIS302DL_REG_CTRL2,
LIS302DL_CTRL2_HPFF1);
__reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
__mg_to_threshold(lis, lis->threshold));
__reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
__ms_to_duration(lis, lis->duration));
/* Clear the HP filter "starting point" */
__reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
__reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE |
LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR);
__lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12);
__lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12);
}
}
#if 0
static void _report_btn_single(struct input_dev *inp, int btn)
{
input_report_key(inp, btn, 1);
input_sync(inp);
input_report_key(inp, btn, 0);
}
static void _report_btn_double(struct input_dev *inp, int btn)
{
input_report_key(inp, btn, 1);
input_sync(inp);
input_report_key(inp, btn, 0);
input_sync(inp);
input_report_key(inp, btn, 1);
input_sync(inp);
input_report_key(inp, btn, 0);
}
#endif
static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
{
u8 data[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 2] = {0xC0 | LIS302DL_REG_STATUS};
u8 *read = data + 1;
unsigned long flags;
int mg_per_sample = __threshold_to_mg(lis, 1);
struct spi_message msg;
struct spi_transfer t;
spi_message_init(&msg);
memset(&t, 0, sizeof t);
t.len = sizeof(data);
spi_message_add_tail(&t, &msg);
t.tx_buf = &data[0];
t.rx_buf = &data[0];
/* grab the set of register containing status and XYZ data */
local_irq_save(flags);
/* Should complete without blocking */
if (spi_non_blocking_transfer(lis->spi, &msg) < 0)
dev_err(lis->dev, "Error reading registers\n");
local_irq_restore(flags);
/*
* at the minute the test below fails 50% of the time due to
* a problem with level interrupts causing ISRs to get called twice.
* This is a workaround for that, but actually this test is still
* valid and the information can be used for overrrun stats.
*/
/* has any kind of overrun been observed by the lis302dl? */
if (read[0] & (LIS302DL_STATUS_XOR |
LIS302DL_STATUS_YOR |
LIS302DL_STATUS_ZOR))
lis->overruns++;
/* we have a valid sample set? */
if (read[0] & LIS302DL_STATUS_XYZDA) {
input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
(s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
(s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
input_report_abs(lis->input_dev, ABS_Z, mg_per_sample *
(s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
input_sync(lis->input_dev);
}
if (lis->threshold)
/* acknowledge the wakeup source */
__reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
}
static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
{
struct lis302dl_info *lis = _lis;
lis302dl_bitbang_read_sample(lis);
return IRQ_HANDLED;
}
/* sysfs */
static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", lis->overruns);
}
static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL);
static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
u8 ctrl1;
unsigned long flags;
local_irq_save(flags);
ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
local_irq_restore(flags);
return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
}
static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned long flags;
local_irq_save(flags);
if (!strcmp(buf, "400\n")) {
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
LIS302DL_CTRL1_DR);
lis->flags |= LIS302DL_F_DR;
} else {
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
0);
lis->flags &= ~LIS302DL_F_DR;
}
local_irq_restore(flags);
return count;
}
static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
u_int8_t ctrl1;
unsigned long flags;
local_irq_save(flags);
ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
local_irq_restore(flags);
return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
}
static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned long flags;
local_irq_save(flags);
if (!strcmp(buf, "9.2\n")) {
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
LIS302DL_CTRL1_FS);
lis->flags |= LIS302DL_F_FS;
} else {
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
0);
lis->flags &= ~LIS302DL_F_FS;
}
if (lis->flags & LIS302DL_F_INPUT_OPEN)
__enable_data_collection(lis);
local_irq_restore(flags);
return count;
}
static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
static ssize_t show_threshold(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
/* Display the device view of the threshold setting */
return sprintf(buf, "%d\n", __threshold_to_mg(lis,
__mg_to_threshold(lis, lis->threshold)));
}
static ssize_t set_threshold(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned int val;
if (sscanf(buf, "%u\n", &val) != 1)
return -EINVAL;
/* 8g is the maximum if FS is 1 */
if (val > 8000)
return -ERANGE;
/* Set the threshold and write it out if the device is used */
lis->threshold = val;
if (lis->flags & LIS302DL_F_INPUT_OPEN) {
unsigned long flags;
local_irq_save(flags);
__enable_data_collection(lis);
local_irq_restore(flags);
}
return count;
}
static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold);
static ssize_t show_duration(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", __duration_to_ms(lis,
__ms_to_duration(lis, lis->duration)));
}
static ssize_t set_duration(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned int val;
if (sscanf(buf, "%u\n", &val) != 1)
return -EINVAL;
if (val > 2550)
return -ERANGE;
lis->duration = val;
if (lis->flags & LIS302DL_F_INPUT_OPEN)
__reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
__ms_to_duration(lis, lis->duration));
return count;
}
static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration);
static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
int n = 0;
u8 reg[0x40];
char *end = buf;
unsigned long flags;
local_irq_save(flags);
for (n = 0; n < sizeof(reg); n++)
reg[n] = __reg_read(lis, n);
local_irq_restore(flags);
for (n = 0; n < sizeof(reg); n += 16) {
hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
end += strlen(end);
*end++ = '\n';
*end++ = '\0';
}
return end - buf;
}
static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
/* Configure freefall/wakeup interrupts */
static ssize_t set_wakeup_threshold(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned int threshold;
if (sscanf(buf, "%u\n", &threshold) != 1)
return -EINVAL;
if (threshold > 8000)
return -ERANGE;
/* Zero turns the feature off */
if (threshold == 0) {
if (lis->flags & LIS302DL_F_IRQ_WAKE) {
disable_irq_wake(lis->pdata->interrupt);
lis->flags &= ~LIS302DL_F_IRQ_WAKE;
}
return count;
}
lis->wakeup.threshold = threshold;
if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
enable_irq_wake(lis->pdata->interrupt);
lis->flags |= LIS302DL_F_IRQ_WAKE;
}
return count;
}
static ssize_t show_wakeup_threshold(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
/* All events off? */
if (lis->wakeup.threshold == 0)
return sprintf(buf, "off\n");
return sprintf(buf, "%u\n", lis->wakeup.threshold);
}
static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold,
set_wakeup_threshold);
static ssize_t set_wakeup_duration(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
unsigned int duration;
if (sscanf(buf, "%u\n", &duration) != 1)
return -EINVAL;
if (duration > 2550)
return -ERANGE;
lis->wakeup.duration = duration;
return count;
}
static ssize_t show_wakeup_duration(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lis302dl_info *lis = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", lis->wakeup.duration);
}
static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration,
set_wakeup_duration);
static struct attribute *lis302dl_sysfs_entries[] = {
&dev_attr_sample_rate.attr,
&dev_attr_full_scale.attr,
&dev_attr_threshold.attr,
&dev_attr_duration.attr,
&dev_attr_dump.attr,
&dev_attr_wakeup_threshold.attr,
&dev_attr_wakeup_duration.attr,
&dev_attr_overruns.attr,
NULL
};
static struct attribute_group lis302dl_attr_group = {
.name = NULL,
.attrs = lis302dl_sysfs_entries,
};
/* input device handling and driver core interaction */
static int lis302dl_input_open(struct input_dev *inp)
{
struct lis302dl_info *lis = input_get_drvdata(inp);
unsigned long flags;
local_irq_save(flags);
__enable_data_collection(lis);
lis->flags |= LIS302DL_F_INPUT_OPEN;
local_irq_restore(flags);
return 0;
}
static void lis302dl_input_close(struct input_dev *inp)
{
struct lis302dl_info *lis = input_get_drvdata(inp);
u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
LIS302DL_CTRL1_Zen;
unsigned long flags;
local_irq_save(flags);
/* since the input core already serializes access and makes sure we
* only see close() for the close of the last user, we can safely
* disable the data ready events */
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
lis->flags &= ~LIS302DL_F_INPUT_OPEN;
/* however, don't power down the whole device if still needed */
if (!(lis->flags & LIS302DL_F_WUP_FF ||
lis->flags & LIS302DL_F_WUP_CLICK)) {
__reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
0x00);
}
local_irq_restore(flags);
}
/* get the device to reload its coefficients from EEPROM and wait for it
* to complete
*/
static int __lis302dl_reset_device(struct lis302dl_info *lis)
{
int timeout = 10;
__reg_write(lis, LIS302DL_REG_CTRL2,
LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
while ((__reg_read(lis, LIS302DL_REG_CTRL2)
& LIS302DL_CTRL2_BOOT) && (timeout--))
mdelay(1);
return !!(timeout < 0);
}
static int __devinit lis302dl_probe(struct spi_device *spi)
{
int rc;
struct lis302dl_info *lis;
u_int8_t wai;
unsigned long flags;
struct lis302dl_platform_data *pdata = spi->dev.platform_data;
spi->mode = SPI_MODE_3;
rc = spi_setup(spi);
if (rc < 0) {
dev_err(&spi->dev, "spi_setup failed\n");
return rc;
}
lis = kzalloc(sizeof(*lis), GFP_KERNEL);
if (!lis)
return -ENOMEM;
lis->dev = &spi->dev;
lis->spi = spi;
dev_set_drvdata(lis->dev, lis);
lis->pdata = pdata;
rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
if (rc) {
dev_err(lis->dev, "error creating sysfs group\n");
goto bail_free_lis;
}
/* initialize input layer details */
lis->input_dev = input_allocate_device();
if (!lis->input_dev) {
dev_err(lis->dev, "Unable to allocate input device\n");
goto bail_sysfs;
}
input_set_drvdata(lis->input_dev, lis);
lis->input_dev->name = pdata->name;
/* SPI Bus not defined as a valid bus for input subsystem*/
lis->input_dev->id.bustype = BUS_I2C; /* lie about it */
lis->input_dev->open = lis302dl_input_open;
lis->input_dev->close = lis302dl_input_close;
rc = input_register_device(lis->input_dev);
if (rc) {
dev_err(lis->dev, "error %d registering input device\n", rc);
goto bail_inp_dev;
}
local_irq_save(flags);
/* Configure our IO */
(lis->pdata->lis302dl_suspend_io)(lis, 1);
wai = __reg_read(lis, LIS302DL_REG_WHO_AM_I);
if (wai != LIS302DL_WHO_AM_I_MAGIC) {
dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
dev_set_drvdata(lis->dev, NULL);
rc = -ENODEV;
local_irq_restore(flags);
goto bail_inp_reg;
}
set_bit(EV_ABS, lis->input_dev->evbit);
input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0);
input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0);
input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0);
lis->threshold = 0;
lis->duration = 0;
memset(&lis->wakeup, 0, sizeof(lis->wakeup));
if (__lis302dl_reset_device(lis))
dev_err(lis->dev, "device BOOT reload failed\n");
/* force us powered */
__reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
LIS302DL_CTRL1_Xen |
LIS302DL_CTRL1_Yen |
LIS302DL_CTRL1_Zen);
mdelay(1);
__reg_write(lis, LIS302DL_REG_CTRL2, 0);
__reg_write(lis, LIS302DL_REG_CTRL3,
LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
__reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0);
__reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
__reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0);
/* start off in powered down mode; we power up when someone opens us */
__reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen);
if (pdata->open_drain)
/* switch interrupt to open collector, active-low */
__reg_write(lis, LIS302DL_REG_CTRL3,
LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
else
/* push-pull, active-low */
__reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
__lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_GND);
__lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND);
__reg_read(lis, LIS302DL_REG_STATUS);
__reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
__reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
__reg_read(lis, LIS302DL_REG_CLICK_SRC);
local_irq_restore(flags);
dev_info(lis->dev, "Found %s\n", pdata->name);
lis->pdata = pdata;
set_irq_handler(lis->pdata->interrupt, handle_level_irq);
rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt,
IRQF_TRIGGER_LOW, "lis302dl", lis);
if (rc < 0) {
dev_err(lis->dev, "error requesting IRQ %d\n",
lis->pdata->interrupt);
goto bail_inp_reg;
}
return 0;
bail_inp_reg:
input_unregister_device(lis->input_dev);
bail_inp_dev:
input_free_device(lis->input_dev);
bail_sysfs:
sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group);
bail_free_lis:
kfree(lis);
return rc;
}
static int __devexit lis302dl_remove(struct spi_device *spi)
{
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
unsigned long flags;
/* Disable interrupts */
if (lis->flags & LIS302DL_F_IRQ_WAKE)
disable_irq_wake(lis->pdata->interrupt);
free_irq(lis->pdata->interrupt, lis);
/* Reset and power down the device */
local_irq_save(flags);
__reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
__reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
__reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
local_irq_restore(flags);
/* Cleanup resources */
sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
input_unregister_device(lis->input_dev);
if (lis->input_dev)
input_free_device(lis->input_dev);
dev_set_drvdata(lis->dev, NULL);
kfree(lis);
return 0;
}
#ifdef CONFIG_PM
static u8 regs_to_save[] = {
LIS302DL_REG_CTRL1,
LIS302DL_REG_CTRL2,
LIS302DL_REG_CTRL3,
LIS302DL_REG_FF_WU_CFG_1,
LIS302DL_REG_FF_WU_THS_1,
LIS302DL_REG_FF_WU_DURATION_1,
LIS302DL_REG_FF_WU_CFG_2,
LIS302DL_REG_FF_WU_THS_2,
LIS302DL_REG_FF_WU_DURATION_2,
LIS302DL_REG_CLICK_CFG,
LIS302DL_REG_CLICK_THSY_X,
LIS302DL_REG_CLICK_THSZ,
LIS302DL_REG_CLICK_TIME_LIMIT,
LIS302DL_REG_CLICK_LATENCY,
LIS302DL_REG_CLICK_WINDOW,
};
static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
{
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
unsigned long flags;
u_int8_t tmp;
int n;
/* determine if we want to wake up from the accel. */
if (lis->flags & LIS302DL_F_WUP_CLICK)
return 0;
disable_irq(lis->pdata->interrupt);
local_irq_save(flags);
/*
* When we share SPI over multiple sensors, there is a race here
* that one or more sensors will lose. In that case, the shared
* SPI bus GPIO will be in sleep mode and partially pulled down. So
* we explicitly put our IO into "wake" mode here before the final
* traffic to the sensor.
*/
(lis->pdata->lis302dl_suspend_io)(lis, 1);
/* save registers */
for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
lis->regs[regs_to_save[n]] =
__reg_read(lis, regs_to_save[n]);
/* power down or enable wakeup */
if (lis->wakeup.threshold == 0) {
tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
tmp &= ~LIS302DL_CTRL1_PD;
__reg_write(lis, LIS302DL_REG_CTRL1, tmp);
} else
__enable_wakeup(lis);
/* place our IO to the device in sleep-compatible states */
(lis->pdata->lis302dl_suspend_io)(lis, 0);
local_irq_restore(flags);
return 0;
}
static int lis302dl_resume(struct spi_device *spi)
{
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
unsigned long flags;
int n;
if (lis->flags & LIS302DL_F_WUP_CLICK)
return 0;
local_irq_save(flags);
/* get our IO to the device back in operational states */
(lis->pdata->lis302dl_suspend_io)(lis, 1);
/* resume from powerdown first! */
__reg_write(lis, LIS302DL_REG_CTRL1,
LIS302DL_CTRL1_PD |
LIS302DL_CTRL1_Xen |
LIS302DL_CTRL1_Yen |
LIS302DL_CTRL1_Zen);
mdelay(1);
if (__lis302dl_reset_device(lis))
dev_err(&spi->dev, "device BOOT reload failed\n");
lis->regs[LIS302DL_REG_CTRL1] |= LIS302DL_CTRL1_PD |
LIS302DL_CTRL1_Xen |
LIS302DL_CTRL1_Yen |
LIS302DL_CTRL1_Zen;
/* restore registers after resume */
for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
__reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]);
/* if someone had us open, reset the non-wake threshold stuff */
if (lis->flags & LIS302DL_F_INPUT_OPEN)
__enable_data_collection(lis);
local_irq_restore(flags);
enable_irq(lis->pdata->interrupt);
return 0;
}
#else
#define lis302dl_suspend NULL
#define lis302dl_resume NULL
#endif
static struct spi_driver lis302dl_spi_driver = {
.driver = {
.name = "lis302dl",
.owner = THIS_MODULE,
},
.probe = lis302dl_probe,
.remove = __devexit_p(lis302dl_remove),
.suspend = lis302dl_suspend,
.resume = lis302dl_resume,
};
static int __devinit lis302dl_init(void)
{
return spi_register_driver(&lis302dl_spi_driver);
}
static void __exit lis302dl_exit(void)
{
spi_unregister_driver(&lis302dl_spi_driver);
}
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
MODULE_LICENSE("GPL");
module_init(lis302dl_init);
module_exit(lis302dl_exit);

View file

@ -0,0 +1,593 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
* iPAQ H1940 touchscreen support
*
* ChangeLog
*
* 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
* - added clock (de-)allocation code
*
* 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
* - h1940_ -> s3c2410 (this driver is now also used on the n30
* machines :P)
* - Debug messages are now enabled with the config option
* TOUCHSCREEN_S3C2410_DEBUG
* - Changed the way the value are read
* - Input subsystem should now work
* - Use ioremap and readl/writel
*
* 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
* - Make use of some undocumented features of the touchscreen
* controller
*
* 2007-05-23: Harald Welte <laforge@openmoko.org>
* - Add proper support for S32440
*
* 2008-06-23: Andy Green <andy@openmoko.com>
* - removed averaging system
* - added generic Touchscreen filter stuff
*
* 2008-11-27: Nelson Castillo <arhuaco@freaks-unidos.net>
* - improve interrupt handling
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/timer.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/ts.h>
#include <mach/hardware.h>
#include <plat/regs-adc.h>
#include <linux/touchscreen/ts_filter_chain.h>
/* For ts.dev.id.version */
#define S3C2410TSVERSION 0x0101
#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
#define WAIT4INT(x) (((x)<<8) | \
S3C2410_ADCTSC_YM_SEN | \
S3C2410_ADCTSC_YP_SEN | \
S3C2410_ADCTSC_XP_SEN | \
S3C2410_ADCTSC_XY_PST(3))
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \
S3C2410_ADCTSC_YP_SEN | \
S3C2410_ADCTSC_XP_SEN | \
S3C2410_ADCTSC_AUTO_PST | \
S3C2410_ADCTSC_XY_PST(0))
#define DEBUG_LVL KERN_DEBUG
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("s3c2410 touchscreen driver");
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
static char *s3c2410ts_name = "s3c2410 TouchScreen";
#define TS_RELEASE_TIMEOUT (HZ >> 7 ? HZ >> 7 : 1) /* 8ms (5ms if HZ is 200) */
#define TS_EVENT_FIFO_SIZE (2 << 6) /* must be a power of 2 */
#define TS_STATE_STANDBY 0 /* initial state */
#define TS_STATE_PRESSED 1
#define TS_STATE_RELEASE_PENDING 2
#define TS_STATE_RELEASE 3
/*
* Per-touchscreen data.
*/
struct s3c2410ts {
struct input_dev *dev;
struct ts_filter_chain *chain;
int is_down;
int state;
struct kfifo *event_fifo;
};
static struct s3c2410ts ts;
static void __iomem *base_addr;
/*
* A few low level functions.
*/
static inline void s3c2410_ts_connect(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
}
static void s3c2410_ts_start_adc_conversion(void)
{
writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
base_addr + S3C2410_ADCTSC);
writel(readl(base_addr + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,
base_addr + S3C2410_ADCCON);
}
/*
* Just send the input events.
*/
enum ts_input_event {IE_DOWN = 0, IE_UP};
static void ts_input_report(int event, int coords[])
{
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
static char *s[] = {"down", "up"};
struct timeval tv;
do_gettimeofday(&tv);
#endif
if (event == IE_DOWN) {
input_report_abs(ts.dev, ABS_X, coords[0]);
input_report_abs(ts.dev, ABS_Y, coords[1]);
input_report_key(ts.dev, BTN_TOUCH, 1);
input_report_abs(ts.dev, ABS_PRESSURE, 1);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "T:%06d %6s (X:%03d, Y:%03d)\n",
(int)tv.tv_usec, s[event], coords[0], coords[1]);
#endif
} else {
input_report_key(ts.dev, BTN_TOUCH, 0);
input_report_abs(ts.dev, ABS_PRESSURE, 0);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "T:%06d %6s\n",
(int)tv.tv_usec, s[event]);
#endif
}
input_sync(ts.dev);
}
/*
* Manage the state of the touchscreen.
*/
static void event_send_timer_f(unsigned long data);
static struct timer_list event_send_timer =
TIMER_INITIALIZER(event_send_timer_f, 0, 0);
static void event_send_timer_f(unsigned long data)
{
static int noop_counter;
int event_type;
while (__kfifo_get(ts.event_fifo, (unsigned char *)&event_type,
sizeof(int))) {
int buf[2];
switch (event_type) {
case 'D':
if (ts.state == TS_STATE_RELEASE_PENDING)
/* Ignore short UP event */
ts.state = TS_STATE_PRESSED;
break;
case 'U':
ts.state = TS_STATE_RELEASE_PENDING;
break;
case 'P':
if (ts.is_down) /* stylus_action needs a conversion */
s3c2410_ts_start_adc_conversion();
if (unlikely(__kfifo_get(ts.event_fifo,
(unsigned char *)buf,
sizeof(int) * 2)
!= sizeof(int) * 2))
goto ts_exit_error;
ts_input_report(IE_DOWN, buf);
ts.state = TS_STATE_PRESSED;
break;
default:
goto ts_exit_error;
}
noop_counter = 0;
}
if (noop_counter++ >= 1) {
noop_counter = 0;
if (ts.state == TS_STATE_RELEASE_PENDING) {
/*
* We delay the UP event for a while to avoid jitter.
* If we get a DOWN event we do not send it.
*/
ts_input_report(IE_UP, NULL);
ts.state = TS_STATE_STANDBY;
ts_filter_chain_clear(ts.chain);
}
} else {
mod_timer(&event_send_timer, jiffies + TS_RELEASE_TIMEOUT);
}
return;
ts_exit_error: /* should not happen unless we have a bug */
printk(KERN_ERR __FILE__ ": event_send_timer_f failed\n");
}
/*
* Manage interrupts.
*/
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
int event_type;
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
ts.is_down = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
(!(data1 & S3C2410_ADCDAT0_UPDOWN));
event_type = ts.is_down ? 'D' : 'U';
if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)&event_type,
sizeof(int)) != sizeof(int))) /* should not happen */
printk(KERN_ERR __FILE__": stylus_updown lost event!\n");
if (ts.is_down)
s3c2410_ts_start_adc_conversion();
else
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
mod_timer(&event_send_timer, jiffies + 1);
return IRQ_HANDLED;
}
static irqreturn_t stylus_action(int irq, void *dev_id)
{
int buf[3];
/* Grab the ADC results. */
buf[1] = readl(base_addr + S3C2410_ADCDAT0) &
S3C2410_ADCDAT0_XPDATA_MASK;
buf[2] = readl(base_addr + S3C2410_ADCDAT1) &
S3C2410_ADCDAT1_YPDATA_MASK;
switch (ts_filter_chain_feed(ts.chain, &buf[1])) {
case 0:
/* The filter wants more points. */
s3c2410_ts_start_adc_conversion();
return IRQ_HANDLED;
case 1:
/* We have a point from the filters or no filtering enabled. */
buf[0] = 'P';
break;
default:
printk(KERN_ERR __FILE__
":%d Invalid ts_filter_chain_feed return value.\n",
__LINE__);
case -1:
/* Error. Ignore the event. */
ts_filter_chain_clear(ts.chain);
writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
return IRQ_HANDLED;
};
if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)buf,
sizeof(int) * 3) != sizeof(int) * 3))
printk(KERN_ERR __FILE__":stylus_action bug.\n");
writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
mod_timer(&event_send_timer, jiffies + 1);
return IRQ_HANDLED;
}
static struct clk *adc_clock;
/*
* The functions for inserting/removing us as a module.
*/
static int __init s3c2410ts_probe(struct platform_device *pdev)
{
int rc;
struct s3c2410_ts_mach_info *info;
struct input_dev *input_dev;
int ret = 0;
dev_info(&pdev->dev, "Starting\n");
info = (struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
if (!info)
{
dev_err(&pdev->dev, "Hm... too bad: no platform data for ts\n");
return -EINVAL;
}
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "Entering s3c2410ts_init\n");
#endif
adc_clock = clk_get(NULL, "adc");
if (!adc_clock) {
dev_err(&pdev->dev, "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "got and enabled clock\n");
#endif
base_addr = ioremap(S3C2410_PA_ADC,0x20);
if (base_addr == NULL) {
dev_err(&pdev->dev, "Failed to remap register block\n");
ret = -ENOMEM;
goto bail0;
}
/* If we acutally are a S3C2410: Configure GPIOs */
if (!strcmp(pdev->name, "s3c2410-ts"))
s3c2410_ts_connect();
if ((info->presc & 0xff) > 0)
writel(S3C2410_ADCCON_PRSCEN |
S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
base_addr + S3C2410_ADCCON);
else
writel(0, base_addr+S3C2410_ADCCON);
/* Initialise registers */
if ((info->delay & 0xffff) > 0)
writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);
writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);
/* Initialise input stuff */
memset(&ts, 0, sizeof(struct s3c2410ts));
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&pdev->dev, "Unable to allocate the input device\n");
ret = -ENOMEM;
goto bail1;
}
ts.dev = input_dev;
ts.dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |
BIT_MASK(EV_ABS);
ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
ts.dev->name = s3c2410ts_name;
ts.dev->id.bustype = BUS_RS232;
ts.dev->id.vendor = 0xDEAD;
ts.dev->id.product = 0xBEEF;
ts.dev->id.version = S3C2410TSVERSION;
ts.state = TS_STATE_STANDBY;
ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);
if (IS_ERR(ts.event_fifo)) {
ret = -EIO;
goto bail2;
}
/* create the filter chain set up for the 2 coordinates we produce */
ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);
if (IS_ERR(ts.chain))
goto bail2;
ts_filter_chain_clear(ts.chain);
/* Get irqs */
if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
"s3c2410_action", ts.dev)) {
dev_err(&pdev->dev, "Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
ret = -EIO;
goto bail3;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action", ts.dev)) {
dev_err(&pdev->dev, "Could not allocate ts IRQ_TC !\n");
free_irq(IRQ_ADC, ts.dev);
iounmap(base_addr);
ret = -EIO;
goto bail4;
}
dev_info(&pdev->dev, "Successfully loaded\n");
/* All went ok, so register to the input system */
rc = input_register_device(ts.dev);
if (rc) {
ret = -EIO;
goto bail5;
}
return 0;
bail5:
free_irq(IRQ_TC, ts.dev);
free_irq(IRQ_ADC, ts.dev);
clk_disable(adc_clock);
iounmap(base_addr);
disable_irq(IRQ_TC);
bail4:
disable_irq(IRQ_ADC);
bail3:
ts_filter_chain_destroy(ts.chain);
kfifo_free(ts.event_fifo);
bail2:
input_unregister_device(ts.dev);
bail1:
iounmap(base_addr);
bail0:
return ret;
}
static int s3c2410ts_remove(struct platform_device *pdev)
{
disable_irq(IRQ_ADC);
disable_irq(IRQ_TC);
free_irq(IRQ_TC,ts.dev);
free_irq(IRQ_ADC,ts.dev);
if (adc_clock) {
clk_disable(adc_clock);
clk_put(adc_clock);
adc_clock = NULL;
}
input_unregister_device(ts.dev);
iounmap(base_addr);
ts_filter_chain_destroy(ts.chain);
kfifo_free(ts.event_fifo);
return 0;
}
#ifdef CONFIG_PM
static int s3c2410ts_suspend(struct platform_device *pdev, pm_message_t state)
{
writel(TSC_SLEEP, base_addr+S3C2410_ADCTSC);
writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_STDBM,
base_addr+S3C2410_ADCCON);
disable_irq(IRQ_ADC);
disable_irq(IRQ_TC);
clk_disable(adc_clock);
return 0;
}
static int s3c2410ts_resume(struct platform_device *pdev)
{
struct s3c2410_ts_mach_info *info =
( struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
clk_enable(adc_clock);
mdelay(1);
ts_filter_chain_clear(ts.chain);
enable_irq(IRQ_ADC);
enable_irq(IRQ_TC);
if ((info->presc&0xff) > 0)
writel(S3C2410_ADCCON_PRSCEN |
S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
base_addr+S3C2410_ADCCON);
else
writel(0,base_addr+S3C2410_ADCCON);
/* Initialise registers */
if ((info->delay & 0xffff) > 0)
writel(info->delay & 0xffff, base_addr+S3C2410_ADCDLY);
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
return 0;
}
#else
#define s3c2410ts_suspend NULL
#define s3c2410ts_resume NULL
#endif
static struct platform_driver s3c2410ts_driver = {
.driver = {
.name = "s3c2410-ts",
.owner = THIS_MODULE,
},
.probe = s3c2410ts_probe,
.remove = s3c2410ts_remove,
.suspend = s3c2410ts_suspend,
.resume = s3c2410ts_resume,
};
static struct platform_driver s3c2440ts_driver = {
.driver = {
.name = "s3c2440-ts",
.owner = THIS_MODULE,
},
.probe = s3c2410ts_probe,
.remove = s3c2410ts_remove,
.suspend = s3c2410ts_suspend,
.resume = s3c2410ts_resume,
};
static int __init s3c2410ts_init(void)
{
int rc;
rc = platform_driver_register(&s3c2410ts_driver);
if (rc < 0)
return rc;
rc = platform_driver_register(&s3c2440ts_driver);
if (rc < 0)
platform_driver_unregister(&s3c2410ts_driver);
return rc;
}
static void __exit s3c2410ts_exit(void)
{
platform_driver_unregister(&s3c2440ts_driver);
platform_driver_unregister(&s3c2410ts_driver);
}
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);

View file

@ -0,0 +1,183 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (c) 2008,2009 Andy Green <andy@openmoko.com>
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/touchscreen/ts_filter_chain.h>
#include <linux/touchscreen/ts_filter.h>
/*
* Tux, would you like the following function in /lib?
* It helps us avoid silly code.
*/
/**
* sptrlen - Count how many non-null pointers are in a pointer array
* @arr: The array of pointers
*/
static int sptrlen(const void *arr)
{
/* All pointers have the same size. */
const int **p = (const int **)arr;
int len = 0;
while (*(p++))
len++;
return len;
}
struct ts_filter_chain {
/* All of the filters. */
struct ts_filter **arr;
/* Filters that can propagate values in the chain. */
struct ts_filter **pchain;
/* Length of the pchain array. */
int pchain_len;
/* FIXME: Add a spinlock and use it. */
};
struct ts_filter_chain *ts_filter_chain_create(
struct platform_device *pdev,
const struct ts_filter_chain_configuration conf[],
int count_coords)
{
struct ts_filter_chain *c;
int count = 0;
int len;
BUG_ON((count_coords < 1));
BUG_ON(count_coords > MAX_TS_FILTER_COORDS);
c = kzalloc(sizeof(struct ts_filter_chain), GFP_KERNEL);
if (!c)
goto create_err_1;
len = (sptrlen(conf) + 1);
/* Memory for two null-terminated arrays of filters. */
c->arr = kzalloc(2 * sizeof(struct ts_filter *) * len, GFP_KERNEL);
if (!c->arr)
goto create_err_1;
c->pchain = c->arr + len;
while (conf->api) {
/* TODO: Can we get away with only sending pdev->dev? */
struct ts_filter *f =
(conf->api->create)(pdev, conf->config, count_coords);
if (!f) {
dev_info(&pdev->dev, "Filter %d creation failed\n",
count);
goto create_err_2;
}
f->api = conf->api;
c->arr[count++] = f;
if (f->api->haspoint && f->api->getpoint && f->api->process)
c->pchain[c->pchain_len++] = f;
conf++;
}
dev_info(&pdev->dev, "%d filter(s) initialized\n", count);
return c;
create_err_2:
ts_filter_chain_destroy(c); /* Also frees c. */
create_err_1:
dev_info(&pdev->dev, "Error in filter chain initialization\n");
/*
* FIXME: Individual filters have to return errors this way.
* We only have to forward the errors we find.
*/
return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL_GPL(ts_filter_chain_create);
void ts_filter_chain_destroy(struct ts_filter_chain *c)
{
if (c->arr) {
struct ts_filter **a = c->arr;
while (*a) {
((*a)->api->destroy)(*a);
a++;
}
kfree(c->arr);
}
kfree(c);
}
EXPORT_SYMBOL_GPL(ts_filter_chain_destroy);
void ts_filter_chain_clear(struct ts_filter_chain *c)
{
struct ts_filter **a = c->arr;
while (*a) {
if ((*a)->api->clear)
((*a)->api->clear)(*a);
a++;
}
}
EXPORT_SYMBOL_GPL(ts_filter_chain_clear);
static void ts_filter_chain_scale(struct ts_filter_chain *c, int *coords)
{
struct ts_filter **a = c->arr;
while (*a) {
if ((*a)->api->scale)
((*a)->api->scale)(*a, coords);
a++;
}
}
int ts_filter_chain_feed(struct ts_filter_chain *c, int *coords)
{
int len = c->pchain_len;
int i = len - 1;
if (!c->pchain[0])
return 1; /* Nothing to do. */
BUG_ON(c->pchain[0]->api->haspoint(c->pchain[0]));
if (c->pchain[0]->api->process(c->pchain[0], coords))
return -1;
while (i >= 0 && i < len) {
if (c->pchain[i]->api->haspoint(c->pchain[i])) {
c->pchain[i]->api->getpoint(c->pchain[i], coords);
if (++i < len &&
c->pchain[i]->api->process(c->pchain[i], coords))
return -1; /* Error. */
} else {
i--;
}
}
if (i >= 0) { /* Same as i == len. */
ts_filter_chain_scale(c, coords);
return 1;
}
return 0;
}
EXPORT_SYMBOL_GPL(ts_filter_chain_feed);

View file

@ -0,0 +1,296 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2008,2009 by Openmoko, Inc.
* Author: Nelson Castillo <arhuaco@freaks-unidos.net>
* All rights reserved.
*
*
* This filter is useful to reject samples that are not reliable. We consider
* that a sample is not reliable if it deviates form the Majority.
*
* 1) We collect S samples.
*
* 2) For each dimension:
*
* - We sort the points.
* - Points that are "close enough" are considered to be in the same set.
* - We choose the set with more elements. If more than "threshold"
* points are in this set we use the first and the last point of the set
* to define the valid range for this dimension [min, max], otherwise we
* discard all the points and go to step 1.
*
* 3) We consider the unsorted S samples and try to feed them to the next
* filter in the chain. If one of the points of each sample
* is not in the allowed range for its dimension, we discard the sample.
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/touchscreen/ts_filter_group.h>
struct ts_filter_group {
/* Private filter configuration. */
struct ts_filter_group_configuration *config;
/* Filter API. */
struct ts_filter tsf;
int N; /* How many samples we have. */
int *samples[MAX_TS_FILTER_COORDS]; /* The samples: our input. */
int *group_size; /* Used for temporal computations. */
int *sorted_samples; /* Used for temporal computations. */
int range_max[MAX_TS_FILTER_COORDS]; /* Max. computed ranges. */
int range_min[MAX_TS_FILTER_COORDS]; /* Min. computed ranges. */
int tries_left; /* We finish if we don't get enough samples. */
int ready; /* If we are ready to deliver samples. */
int result; /* Index of the point being returned. */
};
#define ts_filter_to_filter_group(f) \
container_of(f, struct ts_filter_group, tsf)
static void ts_filter_group_clear_internal(struct ts_filter_group *tsfg,
int attempts)
{
tsfg->N = 0;
tsfg->tries_left = attempts;
tsfg->ready = 0;
tsfg->result = 0;
}
static void ts_filter_group_clear(struct ts_filter *tsf)
{
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
}
static struct ts_filter *ts_filter_group_create(
struct platform_device *pdev,
const struct ts_filter_configuration *conf,
int count_coords)
{
struct ts_filter_group *tsfg;
int i;
tsfg = kzalloc(sizeof(struct ts_filter_group), GFP_KERNEL);
if (!tsfg)
return NULL;
tsfg->config = container_of(conf,
struct ts_filter_group_configuration,
config);
tsfg->tsf.count_coords = count_coords;
BUG_ON(tsfg->config->attempts <= 0);
tsfg->samples[0] = kmalloc((2 + count_coords) * sizeof(int) *
tsfg->config->length, GFP_KERNEL);
if (!tsfg->samples[0]) {
kfree(tsfg);
return NULL;
}
for (i = 1; i < count_coords; ++i)
tsfg->samples[i] = tsfg->samples[0] + i * tsfg->config->length;
tsfg->sorted_samples = tsfg->samples[0] + count_coords *
tsfg->config->length;
tsfg->group_size = tsfg->samples[0] + (1 + count_coords) *
tsfg->config->length;
ts_filter_group_clear_internal(tsfg, tsfg->config->attempts);
dev_info(&pdev->dev, "Created Group filter len:%d coords:%d close:%d "
"thresh:%d\n", tsfg->config->length, count_coords,
tsfg->config->close_enough, tsfg->config->threshold);
return &tsfg->tsf;
}
static void ts_filter_group_destroy(struct ts_filter *tsf)
{
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
kfree(tsfg->samples[0]); /* first guy has pointer from kmalloc */
kfree(tsf);
}
static int int_cmp(const void *_a, const void *_b)
{
const int *a = _a;
const int *b = _b;
if (*a > *b)
return 1;
if (*a < *b)
return -1;
return 0;
}
static void ts_filter_group_prepare_next(struct ts_filter *tsf);
static int ts_filter_group_process(struct ts_filter *tsf, int *coords)
{
struct ts_filter_group *tsfg = ts_filter_to_filter_group(tsf);
int n;
int i;
BUG_ON(tsfg->N >= tsfg->config->length);
BUG_ON(tsfg->ready);
for (n = 0; n < tsf->count_coords; n++)
tsfg->samples[n][tsfg->N] = coords[n];
if (++tsfg->N < tsfg->config->length)
return 0; /* We need more samples. */
for (n = 0; n < tsfg->tsf.count_coords; n++) {
int *v = tsfg->sorted_samples;
int ngroups = 0;
int best_size;
int best_idx = 0;
int idx = 0;
memcpy(v, tsfg->samples[n], tsfg->N * sizeof(int));
/*
* FIXME: Remove this sort call. We already have the
* algorithm for this modification. The filter will
* need less points (about half) if there is not a
* lot of noise. Right now we are doing a constant
* amount of work no matter how much noise we are
* dealing with.
*/
sort(v, tsfg->N, sizeof(int), int_cmp, NULL);
tsfg->group_size[0] = 1;
for (i = 1; i < tsfg->N; ++i) {
if (v[i] - v[i - 1] <= tsfg->config->close_enough)
tsfg->group_size[ngroups]++;
else
tsfg->group_size[++ngroups] = 1;
}
ngroups++;
best_size = tsfg->group_size[0];
for (i = 1; i < ngroups; i++) {
idx += tsfg->group_size[i - 1];
if (best_size < tsfg->group_size[i]) {
best_size = tsfg->group_size[i];
best_idx = idx;
}
}
if (best_size < tsfg->config->threshold) {
/* This set is not good enough for us. */
if (--tsfg->tries_left) {
ts_filter_group_clear_internal
(tsfg, tsfg->tries_left);
/* No errors but we need more samples. */
return 0;
}
return 1; /* We give up: error. */
}
tsfg->range_min[n] = v[best_idx];
tsfg->range_max[n] = v[best_idx + best_size - 1];
}
ts_filter_group_prepare_next(tsf);
return 0;
}
/*
* This private function prepares a point that will be returned
* in ts_filter_group_getpoint if it is available. It updates
* the priv->ready state also.
*/
static void ts_filter_group_prepare_next(struct ts_filter *tsf)
{
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
int n;
while (priv->result < priv->N) {
for (n = 0; n < priv->tsf.count_coords; ++n) {
if (priv->samples[n][priv->result] <
priv->range_min[n] ||
priv->samples[n][priv->result] > priv->range_max[n])
break;
}
if (n == priv->tsf.count_coords) /* Sample is OK. */
break;
priv->result++;
}
if (unlikely(priv->result >= priv->N)) { /* No sample to deliver. */
ts_filter_group_clear_internal(priv, priv->config->attempts);
priv->ready = 0;
} else {
priv->ready = 1;
}
}
static int ts_filter_group_haspoint(struct ts_filter *tsf)
{
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
return priv->ready;
}
static void ts_filter_group_getpoint(struct ts_filter *tsf, int *point)
{
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
int n;
BUG_ON(!priv->ready);
for (n = 0; n < priv->tsf.count_coords; n++)
point[n] = priv->samples[n][priv->result];
priv->result++;
/* This call will update priv->ready. */
ts_filter_group_prepare_next(tsf);
}
/*
* Get ready to process the next batch of points, forget
* points we could have delivered.
*/
static void ts_filter_group_scale(struct ts_filter *tsf, int *coords)
{
struct ts_filter_group *priv = ts_filter_to_filter_group(tsf);
ts_filter_group_clear_internal(priv, priv->config->attempts);
}
const struct ts_filter_api ts_filter_group_api = {
.create = ts_filter_group_create,
.destroy = ts_filter_group_destroy,
.clear = ts_filter_group_clear,
.process = ts_filter_group_process,
.haspoint = ts_filter_group_haspoint,
.getpoint = ts_filter_group_getpoint,
.scale = ts_filter_group_scale,
};
EXPORT_SYMBOL_GPL(ts_filter_group_api);

View file

@ -0,0 +1,212 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2008,2009 by Openmoko, Inc.
* Author: Nelson Castillo <arhuaco@freaks-unidos.net>
* All rights reserved.
*
* Linearly scale touchscreen values.
*
* Expose the TS_FILTER_LINEAR_NCONSTANTS for the linear transformation
* using sysfs.
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/touchscreen/ts_filter_linear.h>
struct ts_filter_linear;
/* Sysfs code. */
struct const_obj {
/* The actual private object. */
struct ts_filter_linear *tsfl;
/* Our kobject. */
struct kobject kobj;
};
#define to_const_obj(x) container_of(x, struct const_obj, kobj)
struct const_attribute {
struct attribute attr;
ssize_t (*show)(struct const_obj *const, struct const_attribute *attr,
char *buf);
ssize_t (*store)(struct const_obj *const, struct const_attribute *attr,
const char *buf, size_t count);
};
#define to_const_attr(x) container_of(x, struct const_attribute, attr)
/* Private linear filter structure. */
struct ts_filter_linear {
/* Private configuration for this filter. */
struct ts_filter_linear_configuration *config;
/* Generic filter API. */
struct ts_filter tsf;
/* Linear constants for the transformation. */
int constants[TS_FILTER_LINEAR_NCONSTANTS];
/* Sysfs. */
/* Our const_object. */
struct const_obj c_obj;
/* Our type. We will stick operations to it. */
struct kobj_type const_ktype;
/* Attrs. of the virtual files. */
struct const_attribute kattrs[TS_FILTER_LINEAR_NCONSTANTS];
/* Default Attrs. Always NULL for us. */
struct attribute *attrs[TS_FILTER_LINEAR_NCONSTANTS + 1];
/* Storage for the name of the virtual files. */
char attr_names[TS_FILTER_LINEAR_NCONSTANTS][2];
};
#define ts_filter_to_filter_linear(f) \
container_of(f, struct ts_filter_linear, tsf)
/* Sysfs functions. */
static ssize_t const_attr_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
struct const_attribute *a = to_const_attr(attr);
return a->show(to_const_obj(kobj), a, buf);
}
static ssize_t const_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t len)
{
struct const_attribute *a = to_const_attr(attr);
return a->store(to_const_obj(kobj), a, buf, len);
}
static struct sysfs_ops const_sysfs_ops = {
.show = const_attr_show,
.store = const_attr_store,
};
static void const_release(struct kobject *kobj)
{
kfree(to_const_obj(kobj)->tsfl);
}
static ssize_t const_show(struct const_obj *obj, struct const_attribute *attr,
char *buf)
{
int who;
sscanf(attr->attr.name, "%d", &who);
return sprintf(buf, "%d\n", obj->tsfl->constants[who]);
}
static ssize_t const_store(struct const_obj *obj, struct const_attribute *attr,
const char *buf, size_t count)
{
int who;
sscanf(attr->attr.name, "%d", &who);
sscanf(buf, "%d", &obj->tsfl->constants[who]);
return count;
}
/* Filter functions. */
static struct ts_filter *ts_filter_linear_create(
struct platform_device *pdev,
const struct ts_filter_configuration *conf,
int count_coords)
{
struct ts_filter_linear *tsfl;
int i;
int ret;
tsfl = kzalloc(sizeof(struct ts_filter_linear), GFP_KERNEL);
if (!tsfl)
return NULL;
tsfl->config = container_of(conf,
struct ts_filter_linear_configuration,
config);
tsfl->tsf.count_coords = count_coords;
for (i = 0; i < TS_FILTER_LINEAR_NCONSTANTS; ++i) {
tsfl->constants[i] = tsfl->config->constants[i];
/* sysfs */
sprintf(tsfl->attr_names[i], "%d", i);
tsfl->kattrs[i].attr.name = tsfl->attr_names[i];
tsfl->kattrs[i].attr.mode = 0666;
tsfl->kattrs[i].show = const_show;
tsfl->kattrs[i].store = const_store;
tsfl->attrs[i] = &tsfl->kattrs[i].attr;
}
tsfl->attrs[i] = NULL;
tsfl->const_ktype.sysfs_ops = &const_sysfs_ops;
tsfl->const_ktype.release = const_release;
tsfl->const_ktype.default_attrs = tsfl->attrs;
tsfl->c_obj.tsfl = tsfl; /* kernel frees tsfl in const_release */
ret = kobject_init_and_add(&tsfl->c_obj.kobj, &tsfl->const_ktype,
&pdev->dev.kobj, "calibration");
if (ret) {
kobject_put(&tsfl->c_obj.kobj);
return NULL;
}
dev_info(&pdev->dev, "Created Linear filter coords:%d\n", count_coords);
return &tsfl->tsf;
}
static void ts_filter_linear_destroy(struct ts_filter *tsf)
{
struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
/* Kernel frees tsfl in const_release. */
kobject_put(&tsfl->c_obj.kobj);
}
static void ts_filter_linear_scale(struct ts_filter *tsf, int *coords)
{
struct ts_filter_linear *tsfl = ts_filter_to_filter_linear(tsf);
int *k = tsfl->constants;
int c0 = coords[tsfl->config->coord0];
int c1 = coords[tsfl->config->coord1];
coords[tsfl->config->coord0] = (k[2] + k[0] * c0 + k[1] * c1) / k[6];
coords[tsfl->config->coord1] = (k[5] + k[3] * c0 + k[4] * c1) / k[6];
}
const struct ts_filter_api ts_filter_linear_api = {
.create = ts_filter_linear_create,
.destroy = ts_filter_linear_destroy,
.scale = ts_filter_linear_scale,
};
EXPORT_SYMBOL_GPL(ts_filter_linear_api);

Some files were not shown because too many files have changed in this diff Show more