mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-28 22:57:37 +00:00
7848 lines
224 KiB
Diff
7848 lines
224 KiB
Diff
diff -urN a/arch/arm/mach-kirkwood/dockstar-setup.c b/arch/arm/mach-kirkwood/dockstar-setup.c
|
|
--- a/arch/arm/mach-kirkwood/dockstar-setup.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/dockstar-setup.c 2012-05-10 00:59:12.724802150 +0000
|
|
@@ -19,7 +19,6 @@
|
|
#include <asm/mach-types.h>
|
|
#include <asm/mach/arch.h>
|
|
#include <mach/kirkwood.h>
|
|
-#include <plat/mvsdio.h>
|
|
#include "common.h"
|
|
#include "mpp.h"
|
|
|
|
@@ -33,6 +32,10 @@
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = SZ_4M
|
|
}, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
.name = "root",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = MTDPART_SIZ_FULL
|
|
@@ -45,17 +48,17 @@
|
|
|
|
static struct gpio_led dockstar_led_pins[] = {
|
|
{
|
|
- .name = "dockstar:green:health",
|
|
+ .name = "status:green:health",
|
|
.default_trigger = "default-on",
|
|
.gpio = 46,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "dockstar:orange:misc",
|
|
+ .name = "status:orange:fault",
|
|
.default_trigger = "none",
|
|
.gpio = 47,
|
|
.active_low = 1,
|
|
- },
|
|
+ }
|
|
};
|
|
|
|
static struct gpio_led_platform_data dockstar_led_data = {
|
|
@@ -73,8 +76,8 @@
|
|
|
|
static unsigned int dockstar_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
- MPP46_GPIO, /* LED green */
|
|
- MPP47_GPIO, /* LED orange */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
0
|
|
};
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/goflexhome-setup.c b/arch/arm/mach-kirkwood/goflexhome-setup.c
|
|
--- a/arch/arm/mach-kirkwood/goflexhome-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/goflexhome-setup.c 2012-05-10 00:59:12.724802150 +0000
|
|
@@ -0,0 +1,123 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/goflexhome-setup.c
|
|
+ *
|
|
+ * Seagate GoFlex Home Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition goflexhome_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_2M + SZ_4M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data goflexhome_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data goflexhome_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct gpio_led goflexhome_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 46,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 47,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40,
|
|
+ .active_low = 0,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data goflexhome_led_data = {
|
|
+ .leds = goflexhome_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(goflexhome_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device goflexhome_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &goflexhome_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int goflexhome_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
+ MPP40_GPIO, /* LED White */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init goflexhome_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(goflexhome_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(goflexhome_nand_parts), 60);
|
|
+
|
|
+ if (gpio_request(29, "USB Power Enable") != 0 ||
|
|
+ gpio_direction_output(29, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&goflexhome_ge00_data);
|
|
+ kirkwood_sata_init(&goflexhome_sata_data);
|
|
+
|
|
+ platform_device_register(&goflexhome_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(GOFLEXHOME, "Seagate GoFlex Home")
|
|
+ /* Maintainer: Peter Carmichael <peterjncarm@ovi.com> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = goflexhome_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
+
|
|
diff -urN a/arch/arm/mach-kirkwood/goflexnet-setup.c b/arch/arm/mach-kirkwood/goflexnet-setup.c
|
|
--- a/arch/arm/mach-kirkwood/goflexnet-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/goflexnet-setup.c 2012-05-10 00:59:12.732614942 +0000
|
|
@@ -0,0 +1,176 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/goflexnet-setup.c
|
|
+ *
|
|
+ * Seagate GoFlex Net Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition goflexnet_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_4M
|
|
+ }, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data goflexnet_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data goflexnet_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static struct gpio_led goflexnet_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 46, // 0x4000
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 47, // 0x8000
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left0",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 42, // 0x0400
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 43, // 0x0800
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 44, // 0x1000
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left3",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 45, // 0x2000
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right0",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 38, // 0x0040
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 39, // 0x0080
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40, // 0x0100
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right3",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 41, // 0x0200
|
|
+ .active_low = 0,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data goflexnet_led_data = {
|
|
+ .leds = goflexnet_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(goflexnet_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device goflexnet_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &goflexnet_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int goflexnet_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
+ MPP45_GPIO, /* LED Left Capacity 3 */
|
|
+ MPP44_GPIO, /* LED Left Capacity 2 */
|
|
+ MPP43_GPIO, /* LED Left Capacity 1 */
|
|
+ MPP42_GPIO, /* LED Left Capacity 0 */
|
|
+ MPP41_GPIO, /* LED Right Capacity 3 */
|
|
+ MPP40_GPIO, /* LED Right Capacity 2 */
|
|
+ MPP39_GPIO, /* LED Right Capacity 1 */
|
|
+ MPP38_GPIO, /* LED Right Capacity 0 */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init goflexnet_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(goflexnet_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(goflexnet_nand_parts), 60);
|
|
+
|
|
+ if (gpio_request(29, "USB Power Enable") != 0 ||
|
|
+ gpio_direction_output(29, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&goflexnet_ge00_data);
|
|
+ kirkwood_sata_init(&goflexnet_sata_data);
|
|
+
|
|
+ platform_device_register(&goflexnet_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(GOFLEXNET, "Seagate GoFlex Net")
|
|
+ /* Maintainer: Peter Carmichael <peterjncarm@ovi.com> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = goflexnet_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
+
|
|
diff -urN a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c
|
|
--- a/arch/arm/mach-kirkwood/guruplug-setup.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/guruplug-setup.c 2012-05-10 00:59:12.748240526 +0000
|
|
@@ -57,22 +57,24 @@
|
|
|
|
static struct gpio_led guruplug_led_pins[] = {
|
|
{
|
|
- .name = "guruplug:red:health",
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
.gpio = 46,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:green:health",
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
.gpio = 47,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:red:wmode",
|
|
+ .name = "status:red:wmode",
|
|
.gpio = 48,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:green:wmode",
|
|
+ .name = "status:green:wmode",
|
|
.gpio = 49,
|
|
.active_low = 1,
|
|
},
|
|
diff -urN a/arch/arm/mach-kirkwood/iconnect-setup.c b/arch/arm/mach-kirkwood/iconnect-setup.c
|
|
--- a/arch/arm/mach-kirkwood/iconnect-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/iconnect-setup.c 2012-05-10 00:59:12.748240526 +0000
|
|
@@ -0,0 +1,203 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/iconnect-setup.c
|
|
+ *
|
|
+ * Iomega iConnect Wireless
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/leds.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition iconnect_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_1M + SZ_2M
|
|
+ }, {
|
|
+ .name = "rootfs",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M,
|
|
+ }, {
|
|
+ .name = "data",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data iconnect_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(11),
|
|
+};
|
|
+
|
|
+static struct gpio_led iconnect_led_pins[] = {
|
|
+ {
|
|
+ .name = "iconnect:led_level",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 41,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:power",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 42,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:red:power",
|
|
+ .gpio = 43,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb1",
|
|
+ .gpio = 44,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb2",
|
|
+ .gpio = 45,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb3",
|
|
+ .gpio = 46,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb4",
|
|
+ .gpio = 47,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:otb",
|
|
+ .gpio = 48,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data iconnect_led_data = {
|
|
+ .leds = iconnect_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(iconnect_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device iconnect_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &iconnect_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+#define ICONNECT_GPIO_KEY_RESET 12
|
|
+#define ICONNECT_GPIO_KEY_OTB 35
|
|
+
|
|
+#define ICONNECT_SW_RESET 0x00
|
|
+#define ICONNECT_SW_OTB 0x01
|
|
+
|
|
+static struct gpio_keys_button iconnect_buttons[] = {
|
|
+ {
|
|
+ .type = EV_SW,
|
|
+ .code = ICONNECT_SW_RESET,
|
|
+ .gpio = ICONNECT_GPIO_KEY_RESET,
|
|
+ .desc = "Reset Button",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 100,
|
|
+ },
|
|
+ {
|
|
+ .type = EV_SW,
|
|
+ .code = ICONNECT_SW_OTB,
|
|
+ .gpio = ICONNECT_GPIO_KEY_OTB,
|
|
+ .desc = "OTB Button",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 100,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data iconnect_button_data = {
|
|
+ .buttons = iconnect_buttons,
|
|
+ .nbuttons = ARRAY_SIZE(iconnect_buttons),
|
|
+};
|
|
+
|
|
+static struct platform_device iconnect_button_device = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &iconnect_button_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static unsigned int iconnect_mpp_config[] __initdata = {
|
|
+ MPP12_GPIO, /*Input for reset button*/
|
|
+ MPP35_GPIO, /*Input for OTB button*/
|
|
+ MPP41_GPIO,
|
|
+ MPP42_GPIO,
|
|
+ MPP43_GPIO,
|
|
+ MPP44_GPIO,
|
|
+ MPP45_GPIO,
|
|
+ MPP46_GPIO,
|
|
+ MPP47_GPIO,
|
|
+ MPP48_GPIO,
|
|
+ 0
|
|
+};
|
|
+
|
|
+static struct i2c_board_info __initdata iconnect_i2c_rtc = {
|
|
+ I2C_BOARD_INFO("lm63", 0x4c),
|
|
+};
|
|
+
|
|
+static void __init iconnect_init(void)
|
|
+{
|
|
+ u32 dev, rev;
|
|
+
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(iconnect_mpp_config);
|
|
+
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(iconnect_nand_parts), 60);
|
|
+ kirkwood_ehci_init();
|
|
+
|
|
+ kirkwood_ge00_init(&iconnect_ge00_data);
|
|
+ kirkwood_pcie_id(&dev, &rev);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+
|
|
+ platform_device_register(&iconnect_leds);
|
|
+ platform_device_register(&iconnect_button_device);
|
|
+
|
|
+ kirkwood_i2c_init();
|
|
+ i2c_register_board_info(0, &iconnect_i2c_rtc, 1);
|
|
+
|
|
+}
|
|
+
|
|
+static int __init iconnect_pci_init(void)
|
|
+{
|
|
+ if (machine_is_iconnect())
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(iconnect_pci_init);
|
|
+
|
|
+
|
|
+MACHINE_START(ICONNECT, "Iomega iConnect Wireless")
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = iconnect_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/ionics-stratus-setup.c b/arch/arm/mach-kirkwood/ionics-stratus-setup.c
|
|
--- a/arch/arm/mach-kirkwood/ionics-stratus-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/ionics-stratus-setup.c 2012-05-10 01:08:30.386283774 +0000
|
|
@@ -0,0 +1,136 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/ionics-stratus-setup.c
|
|
+ *
|
|
+ * Ionics Stratus Board Setup arcNumber 4184
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include <plat/mvsdio.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition ionics_stratus_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_4M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data ionics_stratus_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data ionics_stratus_mvsdio_data = {
|
|
+ /* unfortunately the CD signal has not been connected */
|
|
+};
|
|
+
|
|
+static struct gpio_led ionics_stratus_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:led1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 44,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led3",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 36,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led4",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 39,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data ionics_stratus_led_data = {
|
|
+ .leds = ionics_stratus_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(ionics_stratus_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device ionics_stratus_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &ionics_stratus_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int ionics_stratus_mpp_config[] __initdata = {
|
|
+ MPP21_GPIO, /* USB PORT 1 Pw Enable */
|
|
+ MPP32_GPIO, /* USB PORT 2 Pw Enable */
|
|
+ MPP48_GPIO, /* WIFI Power Down */
|
|
+ MPP49_GPIO, /* WIFI Host Wakeup */
|
|
+ MPP42_GPIO, /* WIFI MAC Wakeup */
|
|
+ MPP44_GPIO, /* LED 1 */
|
|
+ MPP40_GPIO, /* LED 2 */
|
|
+ MPP36_GPIO, /* LED 3 */
|
|
+ MPP39_GPIO, /* LED 4 */
|
|
+ MPP23_GPIO, /* BTN 1 */
|
|
+ MPP37_GPIO, /* BTN 2 */
|
|
+ MPP38_GPIO, /* BTN 3 */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init ionics_stratus_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(ionics_stratus_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(ionics_stratus_nand_parts), 25);
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+
|
|
+ kirkwood_ge00_init(&ionics_stratus_ge00_data);
|
|
+ kirkwood_sdio_init(&ionics_stratus_mvsdio_data);
|
|
+
|
|
+ platform_device_register(&ionics_stratus_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(IONICS_STRATUS, "Ionics Plug Computer Plus - Stratus")
|
|
+ /* Maintainer: Mike Brown <mbrown@archlinuxarm.org> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = ionics_stratus_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
|
|
--- a/arch/arm/mach-kirkwood/Kconfig 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/Kconfig 2012-05-10 01:06:25.334731827 +0000
|
|
@@ -64,6 +64,54 @@
|
|
Say 'Y' here if you want your kernel to support the
|
|
Seagate FreeAgent DockStar.
|
|
|
|
+config MACH_GOFLEXNET
|
|
+ bool "Seagate GoFlex Net"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Seagate GoFlex Net.
|
|
+
|
|
+config MACH_GOFLEXHOME
|
|
+ bool "Seagate GoFlex Home"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Seagate GoFlex Home.
|
|
+
|
|
+config MACH_ICONNECT
|
|
+ bool "Iomega iConnect Wireless"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Iomega iConnect Wireless.
|
|
+
|
|
+config MACH_POGOPLUGV4
|
|
+ bool "Pogoplug Series 4"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Pogoplug Series 4.
|
|
+
|
|
+config MACH_POGO_E02
|
|
+ bool "CE Pogoplug E02"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ CloudEngines Pogoplug e02.
|
|
+
|
|
+config MACH_NAS6210
|
|
+ bool "RaidSonic ICY BOX IB-NAS6210"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ RaidSonic ICY BOX IB-NAS6210 device.
|
|
+
|
|
+config MACH_TOPKICK
|
|
+ bool "USI Topkick"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ USI Topkick.
|
|
+
|
|
+config MACH_IONICS_STRATUS
|
|
+ bool "Ionics Stratus"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Ionics Stratus.
|
|
+
|
|
config MACH_OPENRD
|
|
bool
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
|
|
--- a/arch/arm/mach-kirkwood/Makefile 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/Makefile 2012-05-10 01:07:49.330060764 +0000
|
|
@@ -8,6 +8,14 @@
|
|
obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG) += sheevaplug-setup.o
|
|
obj-$(CONFIG_MACH_GURUPLUG) += guruplug-setup.o
|
|
obj-$(CONFIG_MACH_DOCKSTAR) += dockstar-setup.o
|
|
+obj-$(CONFIG_MACH_GOFLEXNET) += goflexnet-setup.o
|
|
+obj-$(CONFIG_MACH_GOFLEXHOME) += goflexhome-setup.o
|
|
+obj-$(CONFIG_MACH_ICONNECT) += iconnect-setup.o
|
|
+obj-$(CONFIG_MACH_POGOPLUGV4) += pogoplugv4-setup.o
|
|
+obj-$(CONFIG_MACH_POGO_E02) += pogo_e02-setup.o
|
|
+obj-$(CONFIG_MACH_NAS6210) += nas6210-setup.o
|
|
+obj-$(CONFIG_MACH_TOPKICK) += topkick-setup.o
|
|
+obj-$(CONFIG_MACH_IONICS_STRATUS) += ionics-stratus-setup.o
|
|
obj-$(CONFIG_MACH_TS219) += ts219-setup.o tsx1x-common.o
|
|
obj-$(CONFIG_MACH_TS41X) += ts41x-setup.o tsx1x-common.o
|
|
obj-$(CONFIG_MACH_OPENRD) += openrd-setup.o
|
|
diff -urN a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h
|
|
--- a/arch/arm/mach-kirkwood/mpp.h 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/mpp.h 2012-05-10 00:59:12.771678903 +0000
|
|
@@ -102,6 +102,7 @@
|
|
#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 1, 0, 1, 1, 1, 1 )
|
|
|
|
#define MPP12_GPO MPP( 12, 0x0, 0, 1, 1, 1, 1, 1, 1 )
|
|
+#define MPP12_GPIO MPP( 12, 0x0, 1, 1, 1, 1, 1, 1, 1 )
|
|
#define MPP12_SD_CLK MPP( 12, 0x1, 0, 1, 1, 1, 1, 1, 1 )
|
|
#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 1, 0, 0, 0, 0, 1 )
|
|
#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 1, 0, 0, 0, 0, 1 )
|
|
diff -urN a/arch/arm/mach-kirkwood/nas6210-setup.c b/arch/arm/mach-kirkwood/nas6210-setup.c
|
|
--- a/arch/arm/mach-kirkwood/nas6210-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/nas6210-setup.c 2012-05-10 00:59:12.779491696 +0000
|
|
@@ -0,0 +1,185 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/nas6210-setup.c
|
|
+ *
|
|
+ * Raidsonic ICYBOX NAS6210 Board Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+#define NAS6210_GPIO_POWER_OFF 24
|
|
+
|
|
+static struct mtd_partition nas6210_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 6*SZ_1M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data nas6210_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(8),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data nas6210_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static struct gpio_led nas6210_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:power",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 25,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:power",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 22,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:usb_copy",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 27,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data nas6210_led_data = {
|
|
+ .leds = nas6210_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(nas6210_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device nas6210_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &nas6210_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button nas6210_buttons[] = {
|
|
+ {
|
|
+ .code = KEY_COPY,
|
|
+ .gpio = 29,
|
|
+ .desc = "USB Copy",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .code = KEY_RESTART,
|
|
+ .gpio = 28,
|
|
+ .desc = "Reset",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data nas6210_button_data = {
|
|
+ .buttons = nas6210_buttons,
|
|
+ .nbuttons = ARRAY_SIZE(nas6210_buttons),
|
|
+};
|
|
+
|
|
+static struct platform_device nas6210_button_device = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &nas6210_button_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int nas6210_mpp_config[] __initdata = {
|
|
+ MPP0_NF_IO2,
|
|
+ MPP1_NF_IO3,
|
|
+ MPP2_NF_IO4,
|
|
+ MPP3_NF_IO5,
|
|
+ MPP4_NF_IO6,
|
|
+ MPP5_NF_IO7,
|
|
+ MPP18_NF_IO0,
|
|
+ MPP19_NF_IO1,
|
|
+ MPP22_GPIO, /* Power LED red */
|
|
+ MPP24_GPIO, /* Power off device */
|
|
+ MPP25_GPIO, /* Power LED green */
|
|
+ MPP27_GPIO, /* USB transfer LED */
|
|
+ MPP28_GPIO, /* Reset button */
|
|
+ MPP29_GPIO, /* USB Copy button */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void nas6210_power_off(void)
|
|
+{
|
|
+ gpio_set_value(NAS6210_GPIO_POWER_OFF, 1);
|
|
+}
|
|
+
|
|
+static void __init nas6210_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(nas6210_mpp_config);
|
|
+
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(nas6210_nand_parts), 25);
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&nas6210_ge00_data);
|
|
+ kirkwood_sata_init(&nas6210_sata_data);
|
|
+ kirkwood_uart0_init();
|
|
+ platform_device_register(&nas6210_leds);
|
|
+ platform_device_register(&nas6210_button_device);
|
|
+ if (gpio_request(NAS6210_GPIO_POWER_OFF, "power-off") == 0 &&
|
|
+ gpio_direction_output(NAS6210_GPIO_POWER_OFF, 0) == 0)
|
|
+ pm_power_off = nas6210_power_off;
|
|
+ else
|
|
+ pr_err("nas6210: failed to configure power-off GPIO\n");
|
|
+}
|
|
+
|
|
+static int __init nas6210_pci_init(void)
|
|
+{
|
|
+ if (machine_is_nas6210()) {
|
|
+ u32 dev, rev;
|
|
+
|
|
+ kirkwood_pcie_id(&dev, &rev);
|
|
+ if (dev == MV88F6282_DEV_ID)
|
|
+ kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
|
|
+ else
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(nas6210_pci_init);
|
|
+
|
|
+MACHINE_START(NAS6210, "RaidSonic ICY BOX IB-NAS6210")
|
|
+ /* Maintainer: <gmbnomis at gmail dot com> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = nas6210_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/pogo_e02-setup.c b/arch/arm/mach-kirkwood/pogo_e02-setup.c
|
|
--- a/arch/arm/mach-kirkwood/pogo_e02-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/pogo_e02-setup.c 2012-05-10 00:59:12.779491696 +0000
|
|
@@ -0,0 +1,114 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/pogo_e02-setup.c
|
|
+ *
|
|
+ * CloudEngines Pogoplug E02 support
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition pogo_e02_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_4M
|
|
+ }, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data pogo_e02_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct gpio_led pogo_e02_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 49,
|
|
+ .active_low = 1,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data pogo_e02_led_data = {
|
|
+ .leds = pogo_e02_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(pogo_e02_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogo_e02_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &pogo_e02_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int pogo_e02_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Orange */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init pogo_e02_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(pogo_e02_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(pogo_e02_nand_parts), 25);
|
|
+
|
|
+ if (gpio_request(29, "USB Power Enable") != 0 ||
|
|
+ gpio_direction_output(29, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
|
|
+ kirkwood_ehci_init();
|
|
+
|
|
+ kirkwood_ge00_init(&pogo_e02_ge00_data);
|
|
+
|
|
+ platform_device_register(&pogo_e02_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(POGO_E02, "Pogoplug E02")
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = pogo_e02_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/pogoplugv4-setup.c b/arch/arm/mach-kirkwood/pogoplugv4-setup.c
|
|
--- a/arch/arm/mach-kirkwood/pogoplugv4-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/pogoplugv4-setup.c 2012-05-10 00:59:12.779491696 +0000
|
|
@@ -0,0 +1,194 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/pogoplugv4-setup.c
|
|
+ *
|
|
+ * Pogoplug Series 4 Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/leds.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/spi/flash.h>
|
|
+#include <linux/spi/spi.h>
|
|
+#include <linux/spi/orion_spi.h>
|
|
+#include <linux/input.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include <plat/mvsdio.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+#define POGOPLUGV4_GPIO_USB_VBUS 10
|
|
+
|
|
+static struct mtd_partition ppv4_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = 2 * SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 3 * SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 3 * SZ_1M
|
|
+ }, {
|
|
+ .name = "failsafe",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_8M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data pogoplugv4_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data pogoplugv4_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button pogoplugv4_button_pins[] = {
|
|
+ {
|
|
+ .code = KEY_EJECTCD,
|
|
+ .gpio = 29,
|
|
+ .desc = "Eject Button",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data pogoplugv4_button_data = {
|
|
+ .buttons = pogoplugv4_button_pins,
|
|
+ .nbuttons = ARRAY_SIZE(pogoplugv4_button_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogoplugv4_buttons = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &pogoplugv4_button_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led pogoplugv4_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 22,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 24,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data pogoplugv4_led_data = {
|
|
+ .leds = pogoplugv4_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(pogoplugv4_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogoplugv4_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &pogoplugv4_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data ppv4_mvsdio_data = {
|
|
+ .gpio_card_detect = 27,
|
|
+};
|
|
+
|
|
+static unsigned int ppv4_mpp_config[] __initdata = {
|
|
+ MPP27_GPIO, /* SD card detect */
|
|
+ MPP29_GPIO, /* Eject button */
|
|
+ MPP22_GPIO, /* Green LED */
|
|
+ MPP24_GPIO, /* Red LED */
|
|
+ MPP12_SD_CLK,
|
|
+ MPP13_SD_CMD,
|
|
+ MPP14_SD_D0,
|
|
+ MPP15_SD_D1,
|
|
+ MPP16_SD_D2,
|
|
+ MPP17_SD_D3,
|
|
+ 0
|
|
+};
|
|
+
|
|
+static const struct flash_platform_data pogoplugv4_spi_slave_data = {
|
|
+ .type = "m25p05-nonjedec",
|
|
+};
|
|
+
|
|
+static struct spi_board_info __initdata pogoplugv4_spi_slave_info[] = {
|
|
+ {
|
|
+ .modalias = "m25p05-nonjedec",
|
|
+ .platform_data = &pogoplugv4_spi_slave_data,
|
|
+ .irq = -1,
|
|
+ .max_speed_hz = 20000000,
|
|
+ .bus_num = 0,
|
|
+ .chip_select = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static void __init pogoplugv4_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(ppv4_mpp_config);
|
|
+
|
|
+ orion_gpio_set_valid(POGOPLUGV4_GPIO_USB_VBUS, 1);
|
|
+ if (gpio_request(POGOPLUGV4_GPIO_USB_VBUS, "USB VBUS") != 0 ||
|
|
+ gpio_direction_output(POGOPLUGV4_GPIO_USB_VBUS, 1) != 0)
|
|
+ pr_err("POGOPLUGV4: failed to setup USB VBUS GPIO\n");
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&pogoplugv4_ge00_data);
|
|
+ kirkwood_sata_init(&pogoplugv4_sata_data);
|
|
+ spi_register_board_info(pogoplugv4_spi_slave_info,
|
|
+ ARRAY_SIZE(pogoplugv4_spi_slave_info));
|
|
+ kirkwood_spi_init();
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(ppv4_nand_parts), 25);
|
|
+ kirkwood_sdio_init(&ppv4_mvsdio_data);
|
|
+ platform_device_register(&pogoplugv4_leds);
|
|
+ platform_device_register(&pogoplugv4_buttons);
|
|
+}
|
|
+
|
|
+static int __init pogoplugv4_pci_init(void)
|
|
+{
|
|
+ if (machine_is_pogoplugv4())
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(pogoplugv4_pci_init);
|
|
+
|
|
+MACHINE_START(POGOPLUGV4, "Pogoplug V4")
|
|
+ /* Maintainer: Kevin Mihelich <kevin@archlinuxarm.org> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = pogoplugv4_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c
|
|
--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c 2012-05-10 00:59:12.849806825 +0000
|
|
@@ -43,7 +43,7 @@
|
|
.phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
};
|
|
|
|
-static struct mv_sata_platform_data sheeva_esata_sata_data = {
|
|
+static struct mv_sata_platform_data esata_sheevaplug_sata_data = {
|
|
.n_ports = 2,
|
|
};
|
|
|
|
@@ -51,7 +51,7 @@
|
|
/* unfortunately the CD signal has not been connected */
|
|
};
|
|
|
|
-static struct mvsdio_platform_data sheeva_esata_mvsdio_data = {
|
|
+static struct mvsdio_platform_data esata_sheevaplug_mvsdio_data = {
|
|
.gpio_write_protect = 44, /* MPP44 used as SD write protect */
|
|
.gpio_card_detect = 47, /* MPP47 used as SD card detect */
|
|
};
|
|
@@ -64,7 +64,13 @@
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "plug:green:health",
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:blue:health",
|
|
.default_trigger = "default-on",
|
|
.gpio = 49,
|
|
.active_low = 1,
|
|
@@ -87,15 +93,18 @@
|
|
static unsigned int sheevaplug_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
MPP46_GPIO, /* LED Red */
|
|
- MPP49_GPIO, /* LED */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Blue */
|
|
0
|
|
};
|
|
|
|
-static unsigned int sheeva_esata_mpp_config[] __initdata = {
|
|
+static unsigned int esata_sheevaplug_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
MPP44_GPIO, /* SD Write Protect */
|
|
MPP47_GPIO, /* SD Card Detect */
|
|
- MPP49_GPIO, /* LED Green */
|
|
+ MPP46_GPIO, /* LED Red */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Blue */
|
|
0
|
|
};
|
|
|
|
@@ -107,8 +116,8 @@
|
|
kirkwood_init();
|
|
|
|
/* setup gpio pin select */
|
|
- if (machine_is_sheeva_esata())
|
|
- kirkwood_mpp_conf(sheeva_esata_mpp_config);
|
|
+ if (machine_is_esata_sheevaplug())
|
|
+ kirkwood_mpp_conf(esata_sheevaplug_mpp_config);
|
|
else
|
|
kirkwood_mpp_conf(sheevaplug_mpp_config);
|
|
|
|
@@ -123,12 +132,12 @@
|
|
kirkwood_ge00_init(&sheevaplug_ge00_data);
|
|
|
|
/* honor lower power consumption for plugs with out eSATA */
|
|
- if (machine_is_sheeva_esata())
|
|
- kirkwood_sata_init(&sheeva_esata_sata_data);
|
|
+ if (machine_is_esata_sheevaplug())
|
|
+ kirkwood_sata_init(&esata_sheevaplug_sata_data);
|
|
|
|
/* enable sd wp and sd cd on plugs with esata */
|
|
- if (machine_is_sheeva_esata())
|
|
- kirkwood_sdio_init(&sheeva_esata_mvsdio_data);
|
|
+ if (machine_is_esata_sheevaplug())
|
|
+ kirkwood_sdio_init(&esata_sheevaplug_mvsdio_data);
|
|
else
|
|
kirkwood_sdio_init(&sheevaplug_mvsdio_data);
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/topkick-setup.c b/arch/arm/mach-kirkwood/topkick-setup.c
|
|
--- a/arch/arm/mach-kirkwood/topkick-setup.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/arch/arm/mach-kirkwood/topkick-setup.c 2012-05-10 00:59:12.849806825 +0000
|
|
@@ -0,0 +1,164 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/topkick-setup.c
|
|
+ *
|
|
+ * USI Topkick Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mtd/nand.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include <plat/mvsdio.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition topkick_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = 0x180000
|
|
+ }, {
|
|
+ .name = "u-boot-env",
|
|
+ .offset = 0x180000,
|
|
+ .size = 128 * 1024
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = 2 * 1024 * 1024,
|
|
+ .size = 6 * 1024 * 1024
|
|
+ }, {
|
|
+ .name = "rootfs",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data topkick_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data topkick_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data topkick_mvsdio_data = {
|
|
+ .gpio_card_detect = 47, /* MPP47 used as SD card detect */
|
|
+};
|
|
+
|
|
+
|
|
+static struct gpio_led topkick_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:blue:disk",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 21,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 37,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:blue:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 38,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 39,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data topkick_led_data = {
|
|
+ .leds = topkick_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(topkick_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device topkick_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &topkick_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int topkick_mpp_config[] __initdata = {
|
|
+ MPP12_SD_CLK, /* SDIO Clock */
|
|
+ MPP13_SD_CMD, /* SDIO Cmd */
|
|
+ MPP14_SD_D0, /* SDIO Data 0 */
|
|
+ MPP15_SD_D1, /* SDIO Data 1 */
|
|
+ MPP16_SD_D2, /* SDIO Data 2 */
|
|
+ MPP17_SD_D3, /* SDIO Data 3 */
|
|
+ MPP21_GPIO, /* LED Blue SATA */
|
|
+ MPP35_GPIO, /* USB Power Enable */
|
|
+ MPP36_GPIO, /* SATA Power Enable */
|
|
+ MPP37_GPIO, /* LED Red System */
|
|
+ MPP38_GPIO, /* LED Blue System */
|
|
+ MPP39_GPIO, /* LED Green Misc/WiFi */
|
|
+ MPP43_GPIO, /* WOL Eth WOL */
|
|
+ MPP44_GPIO, /* SW GW Mode */
|
|
+ MPP45_GPIO, /* SW AP Mode */
|
|
+ MPP46_GPIO, /* SW Power Off */
|
|
+ MPP47_GPIO, /* SDIO Detect */
|
|
+ MPP48_GPIO, /* LED Orange Misc/WiFi */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init topkick_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(topkick_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(topkick_nand_parts), 60);
|
|
+
|
|
+ if (gpio_request(35, "USB Power Enable") != 0 ||
|
|
+ gpio_direction_output(35, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 35 (USB Power Enable)\n");
|
|
+ if (gpio_request(36, "SATA Power Enable") != 0 ||
|
|
+ gpio_direction_output(36, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 36 (SATA Power Enable)\n");
|
|
+ kirkwood_ge00_init(&topkick_ge00_data);
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_sata_init(&topkick_sata_data);
|
|
+ kirkwood_sdio_init(&topkick_mvsdio_data);
|
|
+
|
|
+ platform_device_register(&topkick_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(TOPKICK, "USI Topkick")
|
|
+ /* Maintainer: Mike Brown <mbrown@archlinuxarm.org> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = topkick_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
|
|
--- a/arch/arm/plat-orion/common.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/arch/arm/plat-orion/common.c 2012-05-10 00:59:12.865432409 +0000
|
|
@@ -223,7 +223,9 @@
|
|
/*****************************************************************************
|
|
* GE00
|
|
****************************************************************************/
|
|
-struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
|
|
+struct mv643xx_eth_shared_platform_data orion_ge00_shared_data = {
|
|
+ .tx_csum_limit = 1600,
|
|
+};
|
|
|
|
static struct resource orion_ge00_shared_resources[] = {
|
|
{
|
|
diff -urN a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
|
--- a/drivers/mmc/core/core.c 2012-05-10 00:59:00.232147424 +0000
|
|
+++ b/drivers/mmc/core/core.c 2012-05-10 00:59:12.873245201 +0000
|
|
@@ -399,9 +399,9 @@
|
|
* The limit is really 250 ms, but that is
|
|
* insufficient for some crappy cards.
|
|
*/
|
|
- limit_us = 300000;
|
|
+ limit_us = 500000;
|
|
else
|
|
- limit_us = 100000;
|
|
+ limit_us = 200000;
|
|
|
|
/*
|
|
* SDHC cards always use these fixed values.
|
|
diff -urN a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
|
--- a/drivers/mmc/core/sd.c 2012-05-10 00:59:00.247773008 +0000
|
|
+++ b/drivers/mmc/core/sd.c 2012-05-10 00:59:12.873245201 +0000
|
|
@@ -388,6 +388,15 @@
|
|
return -ENOMEM;
|
|
}
|
|
|
|
+ /*
|
|
+ * Some SDHC cards, notably those with a Sandisk SD controller
|
|
+ * (also found in Kingston products) need a bit of slack
|
|
+ * before successfully handling the SWITCH command. So far,
|
|
+ * cards identifying themselves as "SD04G" and "SD08G" are
|
|
+ * affected
|
|
+ */
|
|
+ udelay(100);
|
|
+
|
|
err = mmc_sd_switch(card, 1, 0, 1, status);
|
|
if (err)
|
|
goto out;
|
|
diff -urN a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
|
|
--- a/drivers/mmc/host/mvsdio.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/mmc/host/mvsdio.c 2012-05-10 00:59:12.888870786 +0000
|
|
@@ -21,6 +21,7 @@
|
|
#include <linux/irq.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/mmc/host.h>
|
|
+#include <linux/mmc/sd.h>
|
|
|
|
#include <asm/sizes.h>
|
|
#include <asm/unaligned.h>
|
|
@@ -148,6 +149,7 @@
|
|
|
|
dev_dbg(host->dev, "cmd %d (hw state 0x%04x)\n",
|
|
cmd->opcode, mvsd_read(MVSD_HW_STATE));
|
|
+ if (cmd->opcode == SD_SWITCH) mdelay(1); /* Voodoo */
|
|
|
|
cmdreg = MVSD_CMD_INDEX(cmd->opcode);
|
|
|
|
diff -urN a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
|
|
--- a/drivers/net/wireless/Kconfig 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/net/wireless/Kconfig 2012-05-10 00:59:12.912309164 +0000
|
|
@@ -51,6 +51,12 @@
|
|
---help---
|
|
A driver for Marvell Libertas 8388 USB devices using thinfirm.
|
|
|
|
+config LIBERTAS_UAP
|
|
+ tristate "Marvell Libertas 8688 micro-AP support"
|
|
+ depends on LIBERTAS && MMC
|
|
+ ---help---
|
|
+ A driver for Marvell Libertas 8688 SDIO micro-AP support.
|
|
+
|
|
config AIRO
|
|
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
|
|
depends on ISA_DMA_API && (PCI || BROKEN)
|
|
diff -urN a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
|
|
--- a/drivers/net/wireless/libertas/Kconfig 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas/Kconfig 2012-05-10 00:59:12.927934748 +0000
|
|
@@ -3,6 +3,7 @@
|
|
depends on CFG80211
|
|
select WIRELESS_EXT
|
|
select WEXT_SPY
|
|
+ select WEXT_PRIV
|
|
select LIB80211
|
|
select FW_LOADER
|
|
---help---
|
|
diff -urN a/drivers/net/wireless/libertas_uap/Makefile b/drivers/net/wireless/libertas_uap/Makefile
|
|
--- a/drivers/net/wireless/libertas_uap/Makefile 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/Makefile 2012-05-10 00:59:12.927934748 +0000
|
|
@@ -0,0 +1,6 @@
|
|
+obj-$(CONFIG_LIBERTAS_UAP) += uap8xxx.o
|
|
+
|
|
+uap8xxx-y += uap_main.o uap_sdio_mmc.o
|
|
+uap8xxx-$(CONFIG_PROC_FS) += uap_proc.o uap_debug.o
|
|
+
|
|
+EXTRA_CFLAGS += -DFPNUM='"52"' -DPXA3XX_DMA_ALIGN -DDEBUG_LEVEL1
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_debug.c b/drivers/net/wireless/libertas_uap/uap_debug.c
|
|
--- a/drivers/net/wireless/libertas_uap/uap_debug.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_debug.c 2012-05-10 00:59:12.927934748 +0000
|
|
@@ -0,0 +1,261 @@
|
|
+/** @file uap_debug.c
|
|
+ * @brief This file contains functions for debug proc file.
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+#ifdef CONFIG_PROC_FS
|
|
+#include "uap_headers.h"
|
|
+
|
|
+/********************************************************
|
|
+ Local Variables
|
|
+********************************************************/
|
|
+
|
|
+#define item_size(n) (sizeof ((uap_adapter *)0)->n)
|
|
+#define item_addr(n) ((u32) &((uap_adapter *)0)->n)
|
|
+
|
|
+#define item_dbg_size(n) (sizeof (((uap_adapter *)0)->dbg.n))
|
|
+#define item_dbg_addr(n) ((u32) &(((uap_adapter *)0)->dbg.n))
|
|
+
|
|
+#define item_dev_size(n) (sizeof ((uap_dev_t *)0)->n)
|
|
+#define item_dev_addr(n) ((u32) &((uap_dev_t *)0)->n)
|
|
+
|
|
+/** MicroAp device offset */
|
|
+#define OFFSET_UAP_DEV 0x01
|
|
+/** Bluetooth adapter offset */
|
|
+#define OFFSET_UAP_ADAPTER 0x02
|
|
+
|
|
+struct debug_data
|
|
+{
|
|
+ /** Name */
|
|
+ char name[32];
|
|
+ /** Size */
|
|
+ u32 size;
|
|
+ /** Address */
|
|
+ u32 addr;
|
|
+ /** Offset */
|
|
+ u32 offset;
|
|
+ /** Flag */
|
|
+ u32 flag;
|
|
+};
|
|
+
|
|
+/* To debug any member of uap_adapter, simply add one line here.
|
|
+ */
|
|
+static struct debug_data items[] = {
|
|
+ {"cmd_sent", item_dev_size(cmd_sent), 0, item_dev_addr(cmd_sent),
|
|
+ OFFSET_UAP_DEV},
|
|
+ {"data_sent", item_dev_size(data_sent), 0, item_dev_addr(data_sent),
|
|
+ OFFSET_UAP_DEV},
|
|
+ {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter),
|
|
+ OFFSET_UAP_ADAPTER},
|
|
+ {"cmd_pending", item_size(cmd_pending), 0, item_addr(cmd_pending),
|
|
+ OFFSET_UAP_ADAPTER},
|
|
+ {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
|
|
+ item_dbg_addr(num_cmd_host_to_card_failure), OFFSET_UAP_ADAPTER},
|
|
+ {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
|
|
+ item_dbg_addr(num_tx_host_to_card_failure), OFFSET_UAP_ADAPTER},
|
|
+ {"psmode", item_size(psmode), 0, item_addr(psmode), OFFSET_UAP_ADAPTER},
|
|
+ {"ps_state", item_size(ps_state), 0, item_addr(ps_state),
|
|
+ OFFSET_UAP_ADAPTER},
|
|
+#ifdef DEBUG_LEVEL1
|
|
+ {"drvdbg", sizeof(drvdbg), (u32) & drvdbg, 0, 0}
|
|
+#endif
|
|
+};
|
|
+
|
|
+static int num_of_items = sizeof(items) / sizeof(items[0]);
|
|
+
|
|
+/********************************************************
|
|
+ Global Variables
|
|
+********************************************************/
|
|
+
|
|
+/********************************************************
|
|
+ Local Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief proc read function
|
|
+ *
|
|
+ * @param page pointer to buffer
|
|
+ * @param s read data starting position
|
|
+ * @param off offset
|
|
+ * @param cnt counter
|
|
+ * @param eof end of file flag
|
|
+ * @param data data to output
|
|
+ * @return number of output data
|
|
+ */
|
|
+static int
|
|
+uap_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
|
|
+{
|
|
+ int val = 0;
|
|
+ char *p = page;
|
|
+ int i;
|
|
+
|
|
+ struct debug_data *d = (struct debug_data *) data;
|
|
+
|
|
+ if (MODULE_GET == 0)
|
|
+ return UAP_STATUS_FAILURE;
|
|
+
|
|
+ for (i = 0; i < num_of_items; i++) {
|
|
+ if (d[i].size == 1)
|
|
+ val = *((u8 *) d[i].addr);
|
|
+ else if (d[i].size == 2)
|
|
+ val = *((u16 *) d[i].addr);
|
|
+ else if (d[i].size == 4)
|
|
+ val = *((u32 *) d[i].addr);
|
|
+
|
|
+ p += sprintf(p, "%s=%d\n", d[i].name, val);
|
|
+ }
|
|
+ MODULE_PUT;
|
|
+ return p - page;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief proc write function
|
|
+ *
|
|
+ * @param f file pointer
|
|
+ * @param buf pointer to data buffer
|
|
+ * @param cnt data number to write
|
|
+ * @param data data to write
|
|
+ * @return number of data
|
|
+ */
|
|
+static int
|
|
+uap_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data)
|
|
+{
|
|
+ int r, i;
|
|
+ char *pdata;
|
|
+ char *p;
|
|
+ char *p0;
|
|
+ char *p1;
|
|
+ char *p2;
|
|
+ struct debug_data *d = (struct debug_data *) data;
|
|
+
|
|
+ if (MODULE_GET == 0)
|
|
+ return UAP_STATUS_FAILURE;
|
|
+
|
|
+ pdata = (char *) kmalloc(cnt, GFP_KERNEL);
|
|
+ if (pdata == NULL) {
|
|
+ MODULE_PUT;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (copy_from_user(pdata, buf, cnt)) {
|
|
+ PRINTM(INFO, "Copy from user failed\n");
|
|
+ kfree(pdata);
|
|
+ MODULE_PUT;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ p0 = pdata;
|
|
+ for (i = 0; i < num_of_items; i++) {
|
|
+ do {
|
|
+ p = strstr(p0, d[i].name);
|
|
+ if (p == NULL)
|
|
+ break;
|
|
+ p1 = strchr(p, '\n');
|
|
+ if (p1 == NULL)
|
|
+ break;
|
|
+ p0 = p1++;
|
|
+ p2 = strchr(p, '=');
|
|
+ if (!p2)
|
|
+ break;
|
|
+ p2++;
|
|
+ r = string_to_number(p2);
|
|
+ if (d[i].size == 1)
|
|
+ *((u8 *) d[i].addr) = (u8) r;
|
|
+ else if (d[i].size == 2)
|
|
+ *((u16 *) d[i].addr) = (u16) r;
|
|
+ else if (d[i].size == 4)
|
|
+ *((u32 *) d[i].addr) = (u32) r;
|
|
+ break;
|
|
+ } while (TRUE);
|
|
+ }
|
|
+ kfree(pdata);
|
|
+#ifdef DEBUG_LEVEL1
|
|
+ printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
|
|
+ printk(KERN_ALERT "INFO (%08lx) %s\n", DBG_INFO,
|
|
+ (drvdbg & DBG_INFO) ? "X" : "");
|
|
+ printk(KERN_ALERT "WARN (%08lx) %s\n", DBG_WARN,
|
|
+ (drvdbg & DBG_WARN) ? "X" : "");
|
|
+ printk(KERN_ALERT "ENTRY (%08lx) %s\n", DBG_ENTRY,
|
|
+ (drvdbg & DBG_ENTRY) ? "X" : "");
|
|
+ printk(KERN_ALERT "CMD_D (%08lx) %s\n", DBG_CMD_D,
|
|
+ (drvdbg & DBG_CMD_D) ? "X" : "");
|
|
+ printk(KERN_ALERT "DAT_D (%08lx) %s\n", DBG_DAT_D,
|
|
+ (drvdbg & DBG_DAT_D) ? "X" : "");
|
|
+ printk(KERN_ALERT "CMND (%08lx) %s\n", DBG_CMND,
|
|
+ (drvdbg & DBG_CMND) ? "X" : "");
|
|
+ printk(KERN_ALERT "DATA (%08lx) %s\n", DBG_DATA,
|
|
+ (drvdbg & DBG_DATA) ? "X" : "");
|
|
+ printk(KERN_ALERT "ERROR (%08lx) %s\n", DBG_ERROR,
|
|
+ (drvdbg & DBG_ERROR) ? "X" : "");
|
|
+ printk(KERN_ALERT "FATAL (%08lx) %s\n", DBG_FATAL,
|
|
+ (drvdbg & DBG_FATAL) ? "X" : "");
|
|
+ printk(KERN_ALERT "MSG (%08lx) %s\n", DBG_MSG,
|
|
+ (drvdbg & DBG_MSG) ? "X" : "");
|
|
+#endif
|
|
+ MODULE_PUT;
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
+/********************************************************
|
|
+ Global Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief create debug proc file
|
|
+ *
|
|
+ * @param priv pointer uap_private
|
|
+ * @param dev pointer net_device
|
|
+ * @return N/A
|
|
+ */
|
|
+void
|
|
+uap_debug_entry(uap_private * priv, struct net_device *dev)
|
|
+{
|
|
+ int i;
|
|
+ struct proc_dir_entry *r;
|
|
+
|
|
+ if (priv->proc_entry == NULL)
|
|
+ return;
|
|
+
|
|
+ for (i = 0; i < num_of_items; i++) {
|
|
+ if (items[i].flag & OFFSET_UAP_ADAPTER)
|
|
+ items[i].addr = items[i].offset + (u32) priv->adapter;
|
|
+ if (items[i].flag & OFFSET_UAP_DEV)
|
|
+ items[i].addr = items[i].offset + (u32) & priv->uap_dev;
|
|
+ }
|
|
+ r = create_proc_entry("debug", 0644, priv->proc_entry);
|
|
+ if (r == NULL)
|
|
+ return;
|
|
+
|
|
+ r->data = &items[0];
|
|
+ r->read_proc = uap_debug_read;
|
|
+ r->write_proc = uap_debug_write;
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
|
|
+ r->owner = THIS_MODULE;
|
|
+#endif
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief remove proc file
|
|
+ *
|
|
+ * @param priv pointer uap_private
|
|
+ * @return N/A
|
|
+ */
|
|
+void
|
|
+uap_debug_remove(uap_private * priv)
|
|
+{
|
|
+ remove_proc_entry("debug", priv->proc_entry);
|
|
+}
|
|
+
|
|
+#endif
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_drv.h b/drivers/net/wireless/libertas_uap/uap_drv.h
|
|
--- a/drivers/net/wireless/libertas_uap/uap_drv.h 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_drv.h 2012-05-10 00:59:12.935747540 +0000
|
|
@@ -0,0 +1,667 @@
|
|
+/** @file uap_drv.h
|
|
+ * @brief This file contains Linux OS related definitions and
|
|
+ * declarations, uAP driver
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _UAP_DRV_H
|
|
+#define _UAP_DRV_H
|
|
+
|
|
+/** Driver release version */
|
|
+#define DRIVER_VERSION "26146"
|
|
+
|
|
+/** True */
|
|
+#ifndef TRUE
|
|
+#define TRUE 1
|
|
+#endif
|
|
+/** False */
|
|
+#ifndef FALSE
|
|
+#define FALSE 0
|
|
+#endif
|
|
+
|
|
+/** Bit definitions */
|
|
+#ifndef BIT
|
|
+#define BIT(x) (1UL << (x))
|
|
+#endif
|
|
+
|
|
+/** Dma addresses are 32-bits wide. */
|
|
+#ifndef __ATTRIB_ALIGN__
|
|
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
|
|
+#endif
|
|
+
|
|
+/** attribute pack */
|
|
+#ifndef __ATTRIB_PACK__
|
|
+#define __ATTRIB_PACK__ __attribute__ ((packed))
|
|
+#endif
|
|
+
|
|
+/** Debug Macro definition*/
|
|
+#ifdef DEBUG_LEVEL1
|
|
+
|
|
+extern u32 drvdbg;
|
|
+
|
|
+/** Debug message control bit definition for drvdbg */
|
|
+/** Debug message */
|
|
+#define DBG_MSG BIT(0)
|
|
+/** Debug fatal message */
|
|
+#define DBG_FATAL BIT(1)
|
|
+/** Debug error message */
|
|
+#define DBG_ERROR BIT(2)
|
|
+/** Debug data message */
|
|
+#define DBG_DATA BIT(3)
|
|
+/** Debug command message */
|
|
+#define DBG_CMND BIT(4)
|
|
+
|
|
+/** Debug data */
|
|
+#define DBG_DAT_D BIT(16)
|
|
+/** Debug command */
|
|
+#define DBG_CMD_D BIT(17)
|
|
+
|
|
+/** Debug entry */
|
|
+#define DBG_ENTRY BIT(28)
|
|
+/** Debug warning */
|
|
+#define DBG_WARN BIT(29)
|
|
+/** Debug info */
|
|
+#define DBG_INFO BIT(30)
|
|
+
|
|
+/** Print info */
|
|
+#define PRINTM_INFO(msg...) {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
|
|
+/** Print warn message */
|
|
+#define PRINTM_WARN(msg...) {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
|
|
+/** Print entry */
|
|
+#define PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
|
|
+/** Print cmd_d */
|
|
+#define PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
|
|
+/** Print data_d */
|
|
+#define PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
|
|
+/** Print command */
|
|
+#define PRINTM_CMND(msg...) {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
|
|
+/** Print data */
|
|
+#define PRINTM_DATA(msg...) {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
|
|
+/** Print error message */
|
|
+#define PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
|
|
+/** Print fatal message */
|
|
+#define PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
|
|
+/** Print message */
|
|
+#define PRINTM_MSG(msg...) {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
|
|
+/** Print level */
|
|
+#define PRINTM(level,msg...) PRINTM_##level(msg)
|
|
+
|
|
+#else
|
|
+
|
|
+#define PRINTM(level,msg...) do {} while (0)
|
|
+
|
|
+#endif /* DEBUG_LEVEL1 */
|
|
+
|
|
+/** Wait until a condition becomes true */
|
|
+#define ASSERT(cond) \
|
|
+do { \
|
|
+ if (!(cond)) \
|
|
+ PRINTM(INFO, "ASSERT: %s, %s:%i\n", \
|
|
+ __FUNCTION__, __FILE__, __LINE__); \
|
|
+} while(0)
|
|
+
|
|
+/** Log enrty point for debugging */
|
|
+#define ENTER() PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
|
|
+ __FILE__, __LINE__)
|
|
+/** Log exit point for debugging */
|
|
+#define LEAVE() PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
|
|
+ __FILE__, __LINE__)
|
|
+
|
|
+#ifdef DEBUG_LEVEL1
|
|
+/** Dump buffer length */
|
|
+#define DBG_DUMP_BUF_LEN 64
|
|
+/** Maximum dump per line */
|
|
+#define MAX_DUMP_PER_LINE 16
|
|
+/** Data dump length */
|
|
+#define DATA_DUMP_LEN 32
|
|
+
|
|
+static inline void
|
|
+hexdump(char *prompt, u8 * buf, int len)
|
|
+{
|
|
+ int i;
|
|
+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
|
|
+ char *ptr = dbgdumpbuf;
|
|
+
|
|
+ printk(KERN_DEBUG "%s:\n", prompt);
|
|
+ for (i = 1; i <= len; i++) {
|
|
+ ptr += sprintf(ptr, "%02x ", *buf);
|
|
+ buf++;
|
|
+ if (i % MAX_DUMP_PER_LINE == 0) {
|
|
+ *ptr = 0;
|
|
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
|
|
+ ptr = dbgdumpbuf;
|
|
+ }
|
|
+ }
|
|
+ if (len % MAX_DUMP_PER_LINE) {
|
|
+ *ptr = 0;
|
|
+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
|
|
+ }
|
|
+}
|
|
+
|
|
+/** Debug command */
|
|
+#define DBG_HEXDUMP_CMD_D(x,y,z) {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
|
|
+/** Debug data */
|
|
+#define DBG_HEXDUMP_DAT_D(x,y,z) {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
|
|
+/** Debug hexdump */
|
|
+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
|
|
+/** hexdump */
|
|
+#define HEXDUMP(x,y,z) {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
|
|
+#else
|
|
+/** Do nothing since debugging is not turned on */
|
|
+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
|
|
+/** Do nothing since debugging is not turned on */
|
|
+#define HEXDUMP(x,y,z) do {} while (0)
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * Typedefs
|
|
+ */
|
|
+/** Unsigned char */
|
|
+typedef u8 BOOLEAN;
|
|
+
|
|
+/*
|
|
+ * OS macro definitions
|
|
+ */
|
|
+/** OS macro to get time */
|
|
+#define os_time_get() jiffies
|
|
+
|
|
+/** OS macro to update transfer start time */
|
|
+#define UpdateTransStart(dev) { \
|
|
+ dev->trans_start = jiffies; \
|
|
+}
|
|
+
|
|
+/** Try to get a reference to the module */
|
|
+#define MODULE_GET try_module_get(THIS_MODULE)
|
|
+/** Decrease module reference count */
|
|
+#define MODULE_PUT module_put(THIS_MODULE)
|
|
+
|
|
+/** OS macro to initialize semaphore */
|
|
+#define OS_INIT_SEMAPHORE(x) sema_init(x,1)
|
|
+/** OS macro to acquire blocking semaphore */
|
|
+#define OS_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
|
|
+/** OS macro to acquire non-blocking semaphore */
|
|
+#define OS_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
|
|
+/** OS macro to release semaphore */
|
|
+#define OS_REL_SEMAPHORE(x) up(x)
|
|
+
|
|
+static inline void
|
|
+os_sched_timeout(u32 millisec)
|
|
+{
|
|
+ set_current_state(TASK_INTERRUPTIBLE);
|
|
+ schedule_timeout((millisec * HZ) / 1000);
|
|
+}
|
|
+
|
|
+/** Maximum size of ethernet packet */
|
|
+#define MRVDRV_MAXIMUM_ETH_PACKET_SIZE 1514
|
|
+
|
|
+/** Maximum size of multicast list */
|
|
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
|
|
+
|
|
+/** Find minimum */
|
|
+#ifndef MIN
|
|
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
+#endif
|
|
+
|
|
+/** Find maximum */
|
|
+#ifndef MAX
|
|
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
+#endif
|
|
+
|
|
+/** Find number of elements */
|
|
+#ifndef NELEMENTS
|
|
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
|
|
+#endif
|
|
+
|
|
+/** Buffer Constants */
|
|
+
|
|
+/** Size of command buffer */
|
|
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
|
|
+
|
|
+/** Length of device length */
|
|
+#define DEV_NAME_LEN 32
|
|
+
|
|
+/** Length of ethernet address */
|
|
+#ifndef ETH_ALEN
|
|
+#define ETH_ALEN 6
|
|
+#endif
|
|
+
|
|
+/** Default watchdog timeout */
|
|
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (2 * HZ)
|
|
+
|
|
+/** Success */
|
|
+#define UAP_STATUS_SUCCESS (0)
|
|
+/** Failure */
|
|
+#define UAP_STATUS_FAILURE (-1)
|
|
+/** Not accepted */
|
|
+#define UAP_STATUS_NOT_ACCEPTED (-2)
|
|
+
|
|
+/** Max loop count (* 100ms) for waiting device ready at init time */
|
|
+#define MAX_WAIT_DEVICE_READY_COUNT 50
|
|
+
|
|
+/** Tx high watermark. Stop Tx queue after this is crossed */
|
|
+#define TX_HIGH_WATERMARK 4
|
|
+/** Tx low watermark. Restart Tx queue after this is crossed */
|
|
+#define TX_LOW_WATERMARK 2
|
|
+
|
|
+/** Netlink protocol number */
|
|
+#define NETLINK_MARVELL (MAX_LINKS - 1)
|
|
+/** Netlink maximum payload size */
|
|
+#define NL_MAX_PAYLOAD 1024
|
|
+/** Netlink multicast group number */
|
|
+#define NL_MULTICAST_GROUP 1
|
|
+
|
|
+/** 20 seconds */
|
|
+#define MRVDRV_TIMER_20S 20000
|
|
+
|
|
+/** Host Command option for wait till Send */
|
|
+#define HostCmd_OPTION_WAITFORSEND 0x0001
|
|
+/** Host Command option for wait for RSP */
|
|
+#define HostCmd_OPTION_WAITFORRSP 0x0002
|
|
+/** Host Command option for wait for RSP or Timeout */
|
|
+#define HostCmd_OPTION_WAITFORRSP_TIMEOUT 0x0003
|
|
+/** Host Command option for wait for RSP of sleep confirm */
|
|
+#define HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM 0x0004
|
|
+
|
|
+/** Sleep until a condition gets true or a timeout elapses */
|
|
+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
|
|
+ wait_event_interruptible_timeout(waitq, cond, ((timeout) * HZ / 1000))
|
|
+
|
|
+/** Private command ID to Host command */
|
|
+#define UAPHOSTCMD (SIOCDEVPRIVATE + 1)
|
|
+
|
|
+/** Private command ID to Power Mode */
|
|
+#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3)
|
|
+/** sleep_param */
|
|
+typedef struct _ps_sleep_param
|
|
+{
|
|
+ /** control bitmap */
|
|
+ u32 ctrl_bitmap;
|
|
+ /** minimum sleep period (micro second) */
|
|
+ u32 min_sleep;
|
|
+ /** maximum sleep period (micro second) */
|
|
+ u32 max_sleep;
|
|
+} ps_sleep_param;
|
|
+
|
|
+/** inactivity sleep_param */
|
|
+typedef struct _inact_sleep_param
|
|
+{
|
|
+ /** inactivity timeout (micro second) */
|
|
+ u32 inactivity_to;
|
|
+ /** miniumu awake period (micro second) */
|
|
+ u32 min_awake;
|
|
+ /** maximum awake period (micro second) */
|
|
+ u32 max_awake;
|
|
+} inact_sleep_param;
|
|
+
|
|
+/** flag for ps mode */
|
|
+#define PS_FLAG_PS_MODE 1
|
|
+/** flag for sleep param */
|
|
+#define PS_FLAG_SLEEP_PARAM 2
|
|
+/** flag for inactivity sleep param */
|
|
+#define PS_FLAG_INACT_SLEEP_PARAM 4
|
|
+
|
|
+/** Disable power mode */
|
|
+#define PS_MODE_DISABLE 0
|
|
+/** Enable periodic dtim ps */
|
|
+#define PS_MODE_PERIODIC_DTIM 1
|
|
+/** Enable inactivity ps */
|
|
+#define PS_MODE_INACTIVITY 2
|
|
+
|
|
+/** sleep parameter */
|
|
+#define SLEEP_PARAMETER 1
|
|
+/** inactivity sleep parameter */
|
|
+#define INACTIVITY_SLEEP_PARAMETER 2
|
|
+/** ps_mgmt */
|
|
+typedef struct _ps_mgmt
|
|
+{
|
|
+ /** flags for valid field */
|
|
+ u16 flags;
|
|
+ /** power mode */
|
|
+ u16 ps_mode;
|
|
+ /** sleep param */
|
|
+ ps_sleep_param sleep_param;
|
|
+ /** inactivity sleep param */
|
|
+ inact_sleep_param inact_param;
|
|
+} ps_mgmt;
|
|
+
|
|
+/** Semaphore structure */
|
|
+typedef struct semaphore SEMAPHORE;
|
|
+
|
|
+/** Global Varibale Declaration */
|
|
+/** Private data structure of the device */
|
|
+typedef struct _uap_private uap_private;
|
|
+/** Adapter data structure of the device */
|
|
+typedef struct _uap_adapter uap_adapter;
|
|
+/** private structure */
|
|
+extern uap_private *uappriv;
|
|
+
|
|
+/** ENUM definition*/
|
|
+
|
|
+/** Hardware status codes */
|
|
+typedef enum _HARDWARE_STATUS
|
|
+{
|
|
+ HWReady,
|
|
+ HWInitializing,
|
|
+ HWReset,
|
|
+ HWClosing,
|
|
+ HWNotReady
|
|
+} HARDWARE_STATUS;
|
|
+
|
|
+/** info for debug purpose */
|
|
+typedef struct _uap_dbg
|
|
+{
|
|
+ /** Number of host to card command failures */
|
|
+ u32 num_cmd_host_to_card_failure;
|
|
+ /** Number of host to card Tx failures */
|
|
+ u32 num_tx_host_to_card_failure;
|
|
+} uap_dbg;
|
|
+
|
|
+/** Set thread state */
|
|
+#define OS_SET_THREAD_STATE(x) set_current_state(x)
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ /** Task */
|
|
+ struct task_struct *task;
|
|
+ /** Queue */
|
|
+ wait_queue_head_t waitQ;
|
|
+ /** PID */
|
|
+ pid_t pid;
|
|
+ /** Private structure */
|
|
+ void *priv;
|
|
+} uap_thread;
|
|
+
|
|
+static inline void
|
|
+uap_activate_thread(uap_thread * thr)
|
|
+{
|
|
+ /** Record the thread pid */
|
|
+ thr->pid = current->pid;
|
|
+
|
|
+ /** Initialize the wait queue */
|
|
+ init_waitqueue_head(&thr->waitQ);
|
|
+}
|
|
+
|
|
+static inline void
|
|
+uap_deactivate_thread(uap_thread * thr)
|
|
+{
|
|
+ thr->pid = 0;
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+uap_create_thread(int (*uapfunc) (void *), uap_thread * thr, char *name)
|
|
+{
|
|
+ thr->task = kthread_run(uapfunc, thr, "%s", name);
|
|
+}
|
|
+
|
|
+static inline int
|
|
+uap_terminate_thread(uap_thread * thr)
|
|
+{
|
|
+ /* Check if the thread is active or not */
|
|
+ if (!thr->pid)
|
|
+ return -1;
|
|
+ kthread_stop(thr->task);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/** Data structure for the Marvell uAP device */
|
|
+typedef struct _uap_dev
|
|
+{
|
|
+ /** device name */
|
|
+ char name[DEV_NAME_LEN];
|
|
+ /** card pointer */
|
|
+ void *card;
|
|
+ /** IO port */
|
|
+ u32 ioport;
|
|
+ /** Rx unit */
|
|
+ u8 rx_unit;
|
|
+ /** Data sent:
|
|
+ TRUE - Data is sent to fw, no Tx Done received
|
|
+ FALSE - Tx done received for previous Tx */
|
|
+ BOOLEAN data_sent;
|
|
+ /** CMD sent:
|
|
+ TRUE - CMD is sent to fw, no CMD Done received
|
|
+ FALSE - CMD done received for previous CMD */
|
|
+ BOOLEAN cmd_sent;
|
|
+ /** netdev pointer */
|
|
+ struct net_device *netdev;
|
|
+} uap_dev_t, *puap_dev_t;
|
|
+
|
|
+/** Private structure for the MV device */
|
|
+struct _uap_private
|
|
+{
|
|
+ /** Device open */
|
|
+ int open;
|
|
+
|
|
+ /** Device adapter structure */
|
|
+ uap_adapter *adapter;
|
|
+ /** Device structure */
|
|
+ uap_dev_t uap_dev;
|
|
+
|
|
+ /** Net device statistics structure */
|
|
+ struct net_device_stats stats;
|
|
+
|
|
+ /** Number of Tx timeouts */
|
|
+ u32 num_tx_timeout;
|
|
+
|
|
+ /** Media connection status */
|
|
+ BOOLEAN MediaConnected;
|
|
+
|
|
+#ifdef CONFIG_PROC_FS
|
|
+ struct proc_dir_entry *proc_uap;
|
|
+ struct proc_dir_entry *proc_entry;
|
|
+#endif /* CONFIG_PROC_FS */
|
|
+
|
|
+ /** Firmware helper */
|
|
+ const struct firmware *fw_helper;
|
|
+ /** Firmware */
|
|
+ const struct firmware *firmware;
|
|
+ /** Hotplug device */
|
|
+ struct device *hotplug_device;
|
|
+ /** thread to service interrupts */
|
|
+ uap_thread MainThread;
|
|
+ /** Driver lock */
|
|
+ spinlock_t driver_lock;
|
|
+ /** Driver lock flags */
|
|
+ ulong driver_flags;
|
|
+
|
|
+};
|
|
+
|
|
+/** PS_CMD_ConfirmSleep */
|
|
+typedef struct _PS_CMD_ConfirmSleep
|
|
+{
|
|
+ /** SDIO Length */
|
|
+ u16 SDLen;
|
|
+ /** SDIO Type */
|
|
+ u16 SDType;
|
|
+ /** Command */
|
|
+ u16 Command;
|
|
+ /** Size */
|
|
+ u16 Size;
|
|
+ /** Sequence number */
|
|
+ u16 SeqNum;
|
|
+ /** Result */
|
|
+ u16 Result;
|
|
+} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
|
|
+
|
|
+/** Wlan Adapter data structure*/
|
|
+struct _uap_adapter
|
|
+{
|
|
+ /** Power save confirm sleep command */
|
|
+ PS_CMD_ConfirmSleep PSConfirmSleep;
|
|
+ /** Device status */
|
|
+ HARDWARE_STATUS HardwareStatus;
|
|
+ /** Interrupt counter */
|
|
+ u32 IntCounter;
|
|
+ /** Tx packet queue */
|
|
+ struct sk_buff_head tx_queue;
|
|
+ /** Cmd packet queue */
|
|
+ struct sk_buff_head cmd_queue;
|
|
+ /** Command sequence number */
|
|
+ u16 SeqNum;
|
|
+ /** Command buffer */
|
|
+ u8 *CmdBuf;
|
|
+ /** cmd pending flag */
|
|
+ u8 cmd_pending;
|
|
+ /** cmd wait option */
|
|
+ u8 cmd_wait_option;
|
|
+ /** Command buffer length */
|
|
+ u32 CmdSize;
|
|
+ /** Command wait queue */
|
|
+ wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
|
|
+ /** Command wait queue state flag */
|
|
+ u8 CmdWaitQWoken;
|
|
+ /** PnP support */
|
|
+ BOOLEAN SurpriseRemoved;
|
|
+ /** Debug */
|
|
+ uap_dbg dbg;
|
|
+ /** Netlink kernel socket */
|
|
+ struct sock *nl_sk;
|
|
+ /** Semaphore for CMD */
|
|
+ SEMAPHORE CmdSem;
|
|
+ /** Power Save mode */
|
|
+ u8 psmode;
|
|
+ /** Power Save state */
|
|
+ u8 ps_state;
|
|
+ /** Number of wakeup tries */
|
|
+ u32 WakeupTries;
|
|
+};
|
|
+
|
|
+static inline int
|
|
+os_upload_rx_packet(uap_private * priv, struct sk_buff *skb)
|
|
+{
|
|
+ skb->dev = priv->uap_dev.netdev;
|
|
+ skb->protocol = eth_type_trans(skb, priv->uap_dev.netdev);
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+ if (in_interrupt())
|
|
+ netif_rx(skb);
|
|
+ else
|
|
+ netif_rx_ni(skb);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * netif carrier_on/off and start(wake)/stop_queue handling
|
|
+ */
|
|
+static inline void
|
|
+os_carrier_on(uap_private * priv)
|
|
+{
|
|
+ if (!netif_carrier_ok(priv->uap_dev.netdev) &&
|
|
+ (priv->MediaConnected == TRUE)) {
|
|
+ netif_carrier_on(priv->uap_dev.netdev);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void
|
|
+os_carrier_off(uap_private * priv)
|
|
+{
|
|
+ if (netif_carrier_ok(priv->uap_dev.netdev)) {
|
|
+ netif_carrier_off(priv->uap_dev.netdev);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void
|
|
+os_start_queue(uap_private * priv)
|
|
+{
|
|
+ if (netif_queue_stopped(priv->uap_dev.netdev) &&
|
|
+ (priv->MediaConnected == TRUE)) {
|
|
+ netif_wake_queue(priv->uap_dev.netdev);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void
|
|
+os_stop_queue(uap_private * priv)
|
|
+{
|
|
+ if (!netif_queue_stopped(priv->uap_dev.netdev)) {
|
|
+ netif_stop_queue(priv->uap_dev.netdev);
|
|
+ }
|
|
+}
|
|
+
|
|
+/** Interface specific header */
|
|
+#define INTF_HEADER_LEN 4
|
|
+
|
|
+/** headroom alignment for tx packet */
|
|
+#define HEADER_ALIGNMENT 8
|
|
+
|
|
+/** The number of times to try when polling for status bits */
|
|
+#define MAX_POLL_TRIES 100
|
|
+
|
|
+/** Length of SNAP header */
|
|
+#define MRVDRV_SNAP_HEADER_LEN 8
|
|
+
|
|
+/** Extra length of Tx packet buffer */
|
|
+#define EXTRA_LEN 36
|
|
+
|
|
+/** Buffer size for ethernet Tx packets */
|
|
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
|
|
+ (ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
|
|
+
|
|
+/** Buffer size for ethernet Rx packets */
|
|
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
|
|
+ (ETH_FRAME_LEN + sizeof(RxPD) \
|
|
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
|
|
+
|
|
+/** Packet type: data, command & event */
|
|
+typedef enum _mv_type
|
|
+{
|
|
+ MV_TYPE_DAT = 0,
|
|
+ MV_TYPE_CMD = 1,
|
|
+ MV_TYPE_EVENT = 3
|
|
+} mv_type;
|
|
+
|
|
+/** Disable interrupt */
|
|
+#define OS_INT_DISABLE spin_lock_irqsave(&priv->driver_lock, priv->driver_flags)
|
|
+/** Enable interrupt */
|
|
+#define OS_INT_RESTORE spin_unlock_irqrestore(&priv->driver_lock, priv->driver_flags)
|
|
+
|
|
+int uap_process_rx_packet(uap_private * priv, struct sk_buff *skb);
|
|
+void uap_interrupt(uap_private * priv);
|
|
+uap_private *uap_add_card(void *card);
|
|
+int uap_remove_card(void *card);
|
|
+int uap_process_event(uap_private * priv, u8 * payload, uint len);
|
|
+int uap_soft_reset(uap_private * priv);
|
|
+int uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len);
|
|
+
|
|
+#ifdef CONFIG_PROC_FS
|
|
+/** The proc fs interface */
|
|
+void uap_proc_entry(uap_private * priv, struct net_device *dev);
|
|
+void uap_proc_remove(uap_private * priv);
|
|
+int string_to_number(char *s);
|
|
+void uap_debug_entry(uap_private * priv, struct net_device *dev);
|
|
+void uap_debug_remove(uap_private * priv);
|
|
+#endif /* CONFIG_PROC_FS */
|
|
+
|
|
+int sbi_register(void);
|
|
+
|
|
+void sbi_unregister(void);
|
|
+int sbi_register_dev(uap_private * priv);
|
|
+int sbi_unregister_dev(uap_private * priv);
|
|
+int sbi_prog_fw_w_helper(uap_private *);
|
|
+
|
|
+int sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb);
|
|
+int sbi_enable_host_int(uap_private * priv);
|
|
+int sbi_disable_host_int(uap_private * priv);
|
|
+
|
|
+int sbi_get_int_status(uap_private * priv, u8 * ireg);
|
|
+/** Check firmware status */
|
|
+int sbi_check_fw_status(uap_private *, int);
|
|
+int sbi_prog_helper(uap_private *);
|
|
+
|
|
+int sbi_wakeup_firmware(uap_private * priv);
|
|
+
|
|
+#endif /* _UAP_DRV_H */
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_fw.h b/drivers/net/wireless/libertas_uap/uap_fw.h
|
|
--- a/drivers/net/wireless/libertas_uap/uap_fw.h 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_fw.h 2012-05-10 00:59:12.943560332 +0000
|
|
@@ -0,0 +1,359 @@
|
|
+/** @file uap_fw.h
|
|
+ *
|
|
+ * @brief This file contains firmware specific defines.
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+/********************************************************
|
|
+Change log:
|
|
+ 02/26/08: Initial creation
|
|
+********************************************************/
|
|
+
|
|
+#ifndef _UAP_FW_H
|
|
+#define _UAP_FW_H
|
|
+
|
|
+/** uap upload size */
|
|
+#define UAP_UPLD_SIZE 2312
|
|
+/** Packet type Micro AP */
|
|
+#define PKT_TYPE_MICROAP 1
|
|
+/** Packet type client */
|
|
+#define PKT_TYPE_CLIENT 0
|
|
+
|
|
+/** TxPD descriptor */
|
|
+typedef struct _TxPD
|
|
+{
|
|
+ /** Bss Type */
|
|
+ u8 BssType;
|
|
+ /** Bss num */
|
|
+ u8 BssNum;
|
|
+ /** Tx packet length */
|
|
+ u16 TxPktLength;
|
|
+ /** Tx packet offset */
|
|
+ u16 TxPktOffset;
|
|
+ /** Tx packet type */
|
|
+ u16 TxPktType;
|
|
+ /** Tx Control */
|
|
+ u32 TxControl;
|
|
+ /** reserved */
|
|
+ u32 reserved[2];
|
|
+} __ATTRIB_PACK__ TxPD, *PTxPD;
|
|
+
|
|
+/** RxPD Descriptor */
|
|
+typedef struct _RxPD
|
|
+{
|
|
+ /** Bss Type */
|
|
+ u8 BssType;
|
|
+ /** Bss Num */
|
|
+ u8 BssNum;
|
|
+ /** Tx packet length */
|
|
+ u16 RxPktLength;
|
|
+ /** Tx packet offset */
|
|
+ u16 RxPktOffset;
|
|
+} __ATTRIB_PACK__ RxPD, *PRxPD;
|
|
+
|
|
+#ifdef BIG_ENDIAN
|
|
+/** Convert from 16 bit little endian format to CPU format */
|
|
+#define uap_le16_to_cpu(x) le16_to_cpu(x)
|
|
+/** Convert from 32 bit little endian format to CPU format */
|
|
+#define uap_le32_to_cpu(x) le32_to_cpu(x)
|
|
+/** Convert from 64 bit little endian format to CPU format */
|
|
+#define uap_le64_to_cpu(x) le64_to_cpu(x)
|
|
+/** Convert to 16 bit little endian format from CPU format */
|
|
+#define uap_cpu_to_le16(x) cpu_to_le16(x)
|
|
+/** Convert to 32 bit little endian format from CPU format */
|
|
+#define uap_cpu_to_le32(x) cpu_to_le32(x)
|
|
+/** Convert to 64 bit little endian format from CPU format */
|
|
+#define uap_cpu_to_le64(x) cpu_to_le64(x)
|
|
+
|
|
+/** Convert TxPD to little endian format from CPU format */
|
|
+#define endian_convert_TxPD(x); \
|
|
+ { \
|
|
+ (x)->TxPktLength = uap_cpu_to_le16((x)->TxPktLength); \
|
|
+ (x)->TxPktOffset = uap_cpu_to_le32((x)->TxPktOffset); \
|
|
+ (x)->TxControl = uap_cpu_to_le32((x)->TxControl); \
|
|
+ (x)->TxPktType = uap_cpu_to_le32((x)->TxPktType); \
|
|
+ }
|
|
+
|
|
+/** Convert RxPD from little endian format to CPU format */
|
|
+#define endian_convert_RxPD(x); \
|
|
+ { \
|
|
+ (x)->RxPktLength = uap_le16_to_cpu((x)->RxPktLength); \
|
|
+ (x)->RxPktOffset = uap_le32_to_cpu((x)->RxPktOffset); \
|
|
+ }
|
|
+#else /* BIG_ENDIAN */
|
|
+/** Do nothing */
|
|
+#define uap_le16_to_cpu(x) x
|
|
+/** Do nothing */
|
|
+#define uap_le32_to_cpu(x) x
|
|
+/** Do nothing */
|
|
+#define uap_le64_to_cpu(x) x
|
|
+/** Do nothing */
|
|
+#define uap_cpu_to_le16(x) x
|
|
+/** Do nothing */
|
|
+#define uap_cpu_to_le32(x) x
|
|
+/** Do nothing */
|
|
+#define uap_cpu_to_le64(x) x
|
|
+
|
|
+/** Do nothing */
|
|
+#define endian_convert_TxPD(x)
|
|
+/** Do nothing */
|
|
+#define endian_convert_RxPD(x)
|
|
+#endif /* BIG_ENDIAN */
|
|
+
|
|
+/** Host Command ID : Function initialization */
|
|
+#define HostCmd_CMD_FUNC_INIT 0x00a9
|
|
+/** Host Command ID : Function shutdown */
|
|
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
|
|
+
|
|
+/** Host Command id: SYS_INFO */
|
|
+#define HOST_CMD_APCMD_SYS_INFO 0x00ae
|
|
+/** Host Command id: SYS_RESET */
|
|
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
|
|
+/** Host Command id: SYS_CONFIGURE */
|
|
+#define HOST_CMD_APCMD_SYS_CONFIGURE 0x00b0
|
|
+/** Host Command id: BSS_START */
|
|
+#define HOST_CMD_APCMD_BSS_START 0x00b1
|
|
+/** Host Command id: SYS_STOP */
|
|
+#define HOST_CMD_APCMD_BSS_STOP 0x00b2
|
|
+/** Host Command id: STA_LIST */
|
|
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
|
|
+/** Host Command id: STA_FILTER_TABLE */
|
|
+#define HOST_CMD_APCMD_STA_FILTER_TABLE 0x00b4
|
|
+/** Host Command id: STA_DEAUTH */
|
|
+#define HOST_CMD_APCMD_STA_DEAUTH 0x00b5
|
|
+/** Host Command id: SOFT_RESET */
|
|
+#define HOST_CMD_APCMD_SOFT_RESET 0x00d5
|
|
+/** Host Command id: POWER_MGMT_EXT */
|
|
+#define HOST_CMD_POWER_MGMT_EXT 0x00ef
|
|
+/** Host Command id: SLEEP_CONFIRM*/
|
|
+#define HOST_CMD_SLEEP_CONFIRM 0x00d8
|
|
+
|
|
+/** TLV type : SSID */
|
|
+#define TLV_TYPE_SSID 0x0000
|
|
+/** TLV type : Rates */
|
|
+#define TLV_TYPE_RATES 0x0001
|
|
+/** TLV type : PHY DS */
|
|
+#define TLV_TYPE_PHY_DS 0x0003
|
|
+
|
|
+/** TLV Id : Base id */
|
|
+#define PROPRIETARY_TLV_BASE_ID 0x0100
|
|
+/** TLV Id : AP_MAC_ADDRESS */
|
|
+#define MRVL_AP_MAC_ADDRESS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 43)
|
|
+/** TLV Id : Beacon period */
|
|
+#define MRVL_BEACON_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 44)
|
|
+/** TLV Id : Dtim period */
|
|
+#define MRVL_DTIM_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 45)
|
|
+/** TLV Id : Basic rates */
|
|
+#define MRVL_BASIC_RATES_TLV_ID (PROPRIETARY_TLV_BASE_ID + 46)
|
|
+/** TLV Id : Tx Power */
|
|
+#define MRVL_TX_POWER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 47)
|
|
+/** TLV Id : Broadcast SSID control */
|
|
+#define MRVL_BCAST_SSID_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 48)
|
|
+/** TLV Id : Preamble control */
|
|
+#define MRVL_PREAMBLE_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 49)
|
|
+/** TLV Id : Antenna control */
|
|
+#define MRVL_ANTENNA_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 50)
|
|
+/** TLV Id : RTS threshold */
|
|
+#define MRVL_RTS_THRESHOLD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 51)
|
|
+/** TLV Id : Radio control */
|
|
+#define MRVL_RADIO_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 52)
|
|
+/** TLV Id : TX data rate */
|
|
+#define MRVL_TX_DATA_RATE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 53)
|
|
+/** TLV Id : Packet forward control */
|
|
+#define MRVL_PKT_FWD_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 54)
|
|
+/** TLV Id : STA info */
|
|
+#define MRVL_STA_INFO_TLV_ID (PROPRIETARY_TLV_BASE_ID + 55)
|
|
+/** TLV Id : STA MAC address filter */
|
|
+#define MRVL_STA_MAC_ADDR_FILTER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 56)
|
|
+/** TLV Id : STA ageout timer */
|
|
+#define MRVL_STA_AGEOUT_TIMER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 57)
|
|
+/** TLV Id : Security config */
|
|
+#define MRVL_SECURITY_CFG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 58)
|
|
+/** TLV Id : WEP KEY */
|
|
+#define MRVL_WEP_KEY_TLV_ID (PROPRIETARY_TLV_BASE_ID + 59)
|
|
+/** TLV Id : WPA Passphrase */
|
|
+#define MRVL_WPA_PASSPHRASE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 60)
|
|
+
|
|
+/** Action get */
|
|
+#define ACTION_GET 0
|
|
+/** Action set */
|
|
+#define ACTION_SET 1
|
|
+/** Length of ethernet address */
|
|
+#ifndef ETH_ALEN
|
|
+#define ETH_ALEN 6
|
|
+#endif
|
|
+
|
|
+/** HostCmd_DS_GEN */
|
|
+typedef struct
|
|
+{
|
|
+ /** Command */
|
|
+ u16 Command;
|
|
+ /** Size */
|
|
+ u16 Size;
|
|
+ /** Sequence number */
|
|
+ u16 SeqNum;
|
|
+ /** Result */
|
|
+ u16 Result;
|
|
+} __ATTRIB_PACK__ HostCmd_DS_GEN;
|
|
+
|
|
+/** Size of HostCmd_DS_GEN */
|
|
+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
|
|
+
|
|
+/** _HostCmd_HEADER*/
|
|
+typedef struct
|
|
+{
|
|
+ /** Command Header : Command */
|
|
+ u16 Command;
|
|
+ /** Command Header : Size */
|
|
+ u16 Size;
|
|
+} __ATTRIB_PACK__ HostCmd_HEADER;
|
|
+
|
|
+/** HostCmd_SYS_CONFIG */
|
|
+typedef struct _HostCmd_SYS_CONFIG
|
|
+{
|
|
+ /** CMD Action GET/SET*/
|
|
+ u16 Action;
|
|
+ /** Tlv buffer */
|
|
+ u8 TlvBuffer[0];
|
|
+} __ATTRIB_PACK__ HostCmd_SYS_CONFIG;
|
|
+
|
|
+/** HostCmd_DS_POWER_MGMT_EXT */
|
|
+typedef struct _HostCmd_DS_POWER_MGMT_EXT
|
|
+{
|
|
+ /** CMD Action Get/Set*/
|
|
+ u16 action;
|
|
+ /** power mode */
|
|
+ u16 power_mode;
|
|
+} __ATTRIB_PACK__ HostCmd_DS_POWER_MGMT_EXT;
|
|
+
|
|
+/** _HostCmd_DS_COMMAND*/
|
|
+typedef struct _HostCmd_DS_COMMAND
|
|
+{
|
|
+
|
|
+ /** Command Header : Command */
|
|
+ u16 Command;
|
|
+ /** Command Header : Size */
|
|
+ u16 Size;
|
|
+ /** Command Header : Sequence number */
|
|
+ u16 SeqNum;
|
|
+ /** Command Header : Result */
|
|
+ u16 Result;
|
|
+ /** Command Body */
|
|
+ union
|
|
+ {
|
|
+ HostCmd_SYS_CONFIG sys_config;
|
|
+ HostCmd_DS_POWER_MGMT_EXT pm_cfg;
|
|
+
|
|
+ } params;
|
|
+} __ATTRIB_PACK__ HostCmd_DS_COMMAND;
|
|
+
|
|
+/** MrvlIEtypesHeader_*/
|
|
+typedef struct _MrvlIEtypesHeader
|
|
+{
|
|
+ /** Header type */
|
|
+ u16 Type;
|
|
+ /** Header length */
|
|
+ u16 Len;
|
|
+} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
|
|
+
|
|
+/** MrvlIEtypes_Data_t */
|
|
+typedef struct _MrvlIEtypes_Data_t
|
|
+{
|
|
+ /** Header */
|
|
+ MrvlIEtypesHeader_t Header;
|
|
+ /** Data */
|
|
+ u8 Data[1];
|
|
+} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
|
|
+
|
|
+/** MrvlIEtypes_ChanListParamSet_t */
|
|
+typedef struct _MrvlIEtypes_MacAddr_t
|
|
+{
|
|
+ /** Header */
|
|
+ MrvlIEtypesHeader_t Header;
|
|
+ /** AP MAC address */
|
|
+ u8 ApMacAddr[ETH_ALEN];
|
|
+} __ATTRIB_PACK__ MrvlIEtypes_MacAddr_t;
|
|
+
|
|
+/** Event ID: BSS started */
|
|
+#define MICRO_AP_EV_ID_BSS_START 46
|
|
+
|
|
+/** Event ID: BSS idle event */
|
|
+#define MICRO_AP_EV_BSS_IDLE 67
|
|
+
|
|
+/** Event ID: BSS active event */
|
|
+#define MICRO_AP_EV_BSS_ACTIVE 68
|
|
+
|
|
+/** Event ID: PS_AWAKE */
|
|
+#define EVENT_PS_AWAKE 0x0a
|
|
+
|
|
+/** Event ID: PS_SLEEP */
|
|
+#define EVENT_PS_SLEEP 0x0b
|
|
+
|
|
+/** PS_STATE */
|
|
+typedef enum _PS_STATE
|
|
+{
|
|
+ PS_STATE_AWAKE,
|
|
+ PS_STATE_PRE_SLEEP,
|
|
+ PS_STATE_SLEEP
|
|
+} PS_STATE;
|
|
+
|
|
+/** TLV type: AP Sleep param */
|
|
+#define TLV_TYPE_AP_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 106)
|
|
+/** TLV type: AP Inactivity Sleep param */
|
|
+#define TLV_TYPE_AP_INACT_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 107)
|
|
+
|
|
+/** MrvlIEtypes_sleep_param_t */
|
|
+typedef struct _MrvlIEtypes_sleep_param_t
|
|
+{
|
|
+ /** Header */
|
|
+ MrvlIEtypesHeader_t header;
|
|
+ /** control bitmap */
|
|
+ u32 ctrl_bitmap;
|
|
+ /** min_sleep */
|
|
+ u32 min_sleep;
|
|
+ /** max_sleep */
|
|
+ u32 max_sleep;
|
|
+} __ATTRIB_PACK__ MrvlIEtypes_sleep_param_t;
|
|
+
|
|
+/** MrvlIEtypes_inact_sleep_param_t */
|
|
+typedef struct _MrvlIEtypes_inact_sleep_param_t
|
|
+{
|
|
+ /** Header */
|
|
+ MrvlIEtypesHeader_t header;
|
|
+ /** inactivity timeout */
|
|
+ u32 inactivity_to;
|
|
+ /** min_awake */
|
|
+ u32 min_awake;
|
|
+ /** max_awake */
|
|
+ u32 max_awake;
|
|
+} __ATTRIB_PACK__ MrvlIEtypes_inact_sleep_param_t;
|
|
+
|
|
+/** AP_Event */
|
|
+typedef struct _AP_Event
|
|
+{
|
|
+ /** Event ID */
|
|
+ u32 EventId;
|
|
+ /*
|
|
+ * Reserved for STA_ASSOCIATED event and contains
|
|
+ * status information for the MIC_COUNTERMEASURES event.
|
|
+ */
|
|
+ /** Reserved/status */
|
|
+ u16 status;
|
|
+ /** AP MAC address */
|
|
+ u8 MacAddr[ETH_ALEN];
|
|
+} __ATTRIB_PACK__ AP_Event;
|
|
+#endif /* _UAP_FW_H */
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_headers.h b/drivers/net/wireless/libertas_uap/uap_headers.h
|
|
--- a/drivers/net/wireless/libertas_uap/uap_headers.h 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_headers.h 2012-05-10 00:59:12.951373124 +0000
|
|
@@ -0,0 +1,64 @@
|
|
+/** @file uap_headers.h
|
|
+ *
|
|
+ * @brief This file contains all the necessary include file.
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+#ifndef _UAP_HEADERS_H
|
|
+#define _UAP_HEADERS_H
|
|
+
|
|
+/* Linux header files */
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/version.h>
|
|
+#include <linux/param.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/kthread.h>
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
|
|
+#include <linux/semaphore.h>
|
|
+#else
|
|
+#include <asm/semaphore.h>
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
|
|
+#include <linux/config.h>
|
|
+#endif
|
|
+
|
|
+/* Net header files */
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/net.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/if_ether.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <net/sock.h>
|
|
+#include <linux/netlink.h>
|
|
+#include <linux/firmware.h>
|
|
+#include <linux/delay.h>
|
|
+
|
|
+#include "uap_drv.h"
|
|
+#include "uap_fw.h"
|
|
+
|
|
+#include <linux/mmc/sdio.h>
|
|
+#include <linux/mmc/sdio_ids.h>
|
|
+#include <linux/mmc/sdio_func.h>
|
|
+#include <linux/mmc/card.h>
|
|
+#include "uap_sdio_mmc.h"
|
|
+
|
|
+#endif /* _UAP_HEADERS_H */
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_main.c b/drivers/net/wireless/libertas_uap/uap_main.c
|
|
--- a/drivers/net/wireless/libertas_uap/uap_main.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_main.c 2012-05-10 00:59:12.974811500 +0000
|
|
@@ -0,0 +1,1830 @@
|
|
+/** @file uap_main.c
|
|
+ * @brief This file contains the major functions in uAP
|
|
+ * driver. It includes init, exit etc..
|
|
+ * This file also contains the initialization for SW,
|
|
+ * FW and HW
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+/**
|
|
+ * @mainpage uAP Linux Driver
|
|
+ *
|
|
+ * @section overview_sec Overview
|
|
+ *
|
|
+ * This is Linux reference driver for Marvell uAP.
|
|
+ *
|
|
+ * @section copyright_sec Copyright
|
|
+ *
|
|
+ * Copyright (C) 2008, Marvell International Ltd.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "uap_headers.h"
|
|
+
|
|
+/**
|
|
+ * the global variable of a pointer to uap_private
|
|
+ * structure variable
|
|
+ */
|
|
+uap_private *uappriv = NULL;
|
|
+#ifdef DEBUG_LEVEL1
|
|
+#define DEFAULT_DEBUG_MASK (DBG_MSG | DBG_FATAL | DBG_ERROR)
|
|
+u32 drvdbg = DEFAULT_DEBUG_MASK;
|
|
+#endif
|
|
+/** Helper name */
|
|
+char *helper_name = NULL;
|
|
+/** Firmware name */
|
|
+char *fw_name = NULL;
|
|
+
|
|
+/** Semaphore for add/remove card */
|
|
+SEMAPHORE AddRemoveCardSem;
|
|
+
|
|
+/********************************************************
|
|
+ Local Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief This function send sleep confirm command to firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_dnld_sleep_confirm_cmd(uap_private * priv)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ ENTER();
|
|
+ PRINTM(CMND, "Sleep confirm\n");
|
|
+ Adapter->cmd_pending = TRUE;
|
|
+ Adapter->cmd_wait_option = HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM;
|
|
+ ret =
|
|
+ sbi_host_to_card(priv, (u8 *) & Adapter->PSConfirmSleep,
|
|
+ sizeof(PS_CMD_ConfirmSleep));
|
|
+ if (ret != UAP_STATUS_SUCCESS) {
|
|
+ Adapter->ps_state = PS_STATE_AWAKE;
|
|
+ Adapter->cmd_pending = FALSE;
|
|
+ Adapter->cmd_wait_option = FALSE;
|
|
+ }
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function process sleep confirm resp from firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param resp A pointer to resp buf
|
|
+ * @param resp_len resp buf len
|
|
+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ HostCmd_DS_COMMAND *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ ENTER();
|
|
+ PRINTM(CMND, "Sleep confirm resp\n");
|
|
+ if (!resp_len) {
|
|
+ PRINTM(ERROR, "Cmd Size is 0\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ cmd = (HostCmd_DS_COMMAND *) resp;
|
|
+ cmd->Result = uap_le16_to_cpu(cmd->Result);
|
|
+ if (cmd->Result != UAP_STATUS_SUCCESS) {
|
|
+ PRINTM(ERROR, "HOST_CMD_APCMD_PS_SLEEP_CONFIRM fail=%x\n", cmd->Result);
|
|
+ ret = -EFAULT;
|
|
+ }
|
|
+ done:
|
|
+ if (ret == UAP_STATUS_SUCCESS)
|
|
+ Adapter->ps_state = PS_STATE_SLEEP;
|
|
+ else
|
|
+ Adapter->ps_state = PS_STATE_AWAKE;
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function checks condition and prepares to
|
|
+ * send sleep confirm command to firmware if OK.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return n/a
|
|
+ */
|
|
+static void
|
|
+uap_ps_cond_check(uap_private * priv)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+
|
|
+ ENTER();
|
|
+ if (!priv->uap_dev.cmd_sent &&
|
|
+ !Adapter->cmd_pending && !Adapter->IntCounter) {
|
|
+ uap_dnld_sleep_confirm_cmd(priv);
|
|
+ } else {
|
|
+ PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
|
|
+ (priv->uap_dev.cmd_sent) ? "D" : "",
|
|
+ (Adapter->cmd_pending) ? "C" : "",
|
|
+ (Adapter->IntCounter) ? "I" : "");
|
|
+ }
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function add cmd to cmdQ and waiting for response
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param skb A pointer to the skb for process
|
|
+ * @param wait_option Wait option
|
|
+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_process_cmd(uap_private * priv, struct sk_buff *skb, u8 wait_option)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ HostCmd_DS_COMMAND *cmd;
|
|
+ u8 *headptr;
|
|
+ ENTER();
|
|
+ if (Adapter->HardwareStatus != HWReady) {
|
|
+ PRINTM(ERROR, "Hw not ready, uap_process_cmd\n");
|
|
+ kfree(skb);
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ skb->cb[0] = wait_option;
|
|
+ headptr = skb->data;
|
|
+ *(u16 *) & headptr[0] = uap_cpu_to_le16(skb->len);
|
|
+ *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_CMD);
|
|
+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
|
|
+ Adapter->SeqNum++;
|
|
+ cmd->SeqNum = uap_cpu_to_le16(Adapter->SeqNum);
|
|
+ PRINTM(CMND, "process_cmd: %x\n", cmd->Command);
|
|
+ DBG_HEXDUMP(CMD_D, "process_cmd", (u8 *) cmd, cmd->Size);
|
|
+ if (!wait_option) {
|
|
+ skb_queue_tail(&priv->adapter->cmd_queue, skb);
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+ }
|
|
+ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->CmdSem)) {
|
|
+ PRINTM(ERROR, "Acquire semaphore error, uap_prepare_cmd\n");
|
|
+ kfree(skb);
|
|
+ LEAVE();
|
|
+ return -EBUSY;
|
|
+ }
|
|
+ skb_queue_tail(&priv->adapter->cmd_queue, skb);
|
|
+ Adapter->CmdWaitQWoken = FALSE;
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+ /* Sleep until response is generated by FW */
|
|
+ if (wait_option == HostCmd_OPTION_WAITFORRSP_TIMEOUT) {
|
|
+ if (!os_wait_interruptible_timeout
|
|
+ (Adapter->cmdwait_q, Adapter->CmdWaitQWoken, MRVDRV_TIMER_20S)) {
|
|
+ PRINTM(ERROR, "Cmd timeout\n");
|
|
+ Adapter->cmd_pending = FALSE;
|
|
+ ret = -EFAULT;
|
|
+ }
|
|
+ } else
|
|
+ wait_event_interruptible(Adapter->cmdwait_q, Adapter->CmdWaitQWoken);
|
|
+ OS_REL_SEMAPHORE(&Adapter->CmdSem);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Inspect the response buffer for pointers to expected TLVs
|
|
+ *
|
|
+ *
|
|
+ * @param pTlv Pointer to the start of the TLV buffer to parse
|
|
+ * @param tlvBufSize Size of the TLV buffer
|
|
+ * @param reqTlvType request tlv's tlvtype
|
|
+ * @param ppTlv Output parameter: Pointer to the request TLV if found
|
|
+ *
|
|
+ * @return void
|
|
+ */
|
|
+static void
|
|
+uap_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv, int tlvBufSize,
|
|
+ u16 reqTlvType, MrvlIEtypes_Data_t ** ppTlv)
|
|
+{
|
|
+ MrvlIEtypes_Data_t *pCurrentTlv;
|
|
+ int tlvBufLeft;
|
|
+ u16 tlvType;
|
|
+ u16 tlvLen;
|
|
+
|
|
+ ENTER();
|
|
+ pCurrentTlv = pTlv;
|
|
+ tlvBufLeft = tlvBufSize;
|
|
+ *ppTlv = NULL;
|
|
+ PRINTM(INFO, "uap_get_tlv: tlvBufSize = %d, reqTlvType=%x\n", tlvBufSize,
|
|
+ reqTlvType);
|
|
+ while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
|
|
+ tlvType = uap_le16_to_cpu(pCurrentTlv->Header.Type);
|
|
+ tlvLen = uap_le16_to_cpu(pCurrentTlv->Header.Len);
|
|
+ if (reqTlvType == tlvType)
|
|
+ *ppTlv = (MrvlIEtypes_Data_t *) pCurrentTlv;
|
|
+ if (*ppTlv) {
|
|
+ HEXDUMP("TLV Buf", (u8 *) * ppTlv, tlvLen);
|
|
+ break;
|
|
+ }
|
|
+ tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
|
|
+ pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
|
|
+ } /* while */
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function get mac
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
|
|
+ */
|
|
+static int
|
|
+uap_get_mac_address(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_COMMAND *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+ MrvlIEtypes_MacAddr_t *pMacAddrTlv;
|
|
+ MrvlIEtypes_Data_t *pTlv;
|
|
+ u16 tlvBufSize;
|
|
+ ENTER();
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ CmdSize =
|
|
+ S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
|
|
+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_GET);
|
|
+ pMacAddrTlv =
|
|
+ (MrvlIEtypes_MacAddr_t *) (skb->data + INTF_HEADER_LEN + S_DS_GEN +
|
|
+ sizeof(HostCmd_SYS_CONFIG));
|
|
+ pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
|
|
+ pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd SYS_CONFIGURE Query\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ if (!Adapter->CmdSize) {
|
|
+ PRINTM(ERROR, "Cmd Size is 0\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
|
|
+ cmd->Result = uap_le16_to_cpu(cmd->Result);
|
|
+ if (cmd->Result != UAP_STATUS_SUCCESS) {
|
|
+ PRINTM(ERROR, "uap_get_mac_address fail=%x\n", cmd->Result);
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ pTlv =
|
|
+ (MrvlIEtypes_Data_t *) (Adapter->CmdBuf + S_DS_GEN +
|
|
+ sizeof(HostCmd_SYS_CONFIG));
|
|
+ tlvBufSize = Adapter->CmdSize - S_DS_GEN - sizeof(HostCmd_SYS_CONFIG);
|
|
+ uap_get_tlv_ptrs(pTlv, tlvBufSize, MRVL_AP_MAC_ADDRESS_TLV_ID,
|
|
+ (MrvlIEtypes_Data_t **) & pMacAddrTlv);
|
|
+ if (pMacAddrTlv) {
|
|
+ memcpy(priv->uap_dev.netdev->dev_addr, pMacAddrTlv->ApMacAddr,
|
|
+ ETH_ALEN);
|
|
+ HEXDUMP("Original MAC addr", priv->uap_dev.netdev->dev_addr, ETH_ALEN);
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function checks the conditions and sends packet to device
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param skb A pointer to the skb for process
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_process_tx(uap_private * priv, struct sk_buff *skb)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ TxPD *pLocalTxPD;
|
|
+ u8 *headptr;
|
|
+ struct sk_buff *newskb;
|
|
+ int newheadlen;
|
|
+ ENTER();
|
|
+ ASSERT(skb);
|
|
+ if (!skb) {
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+ if (skb_headroom(skb) < (sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT)) {
|
|
+ newheadlen = sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT;
|
|
+ PRINTM(WARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
|
|
+ /* Insufficient skb headroom - allocate a new skb */
|
|
+ newskb = skb_realloc_headroom(skb, newheadlen);
|
|
+ if (unlikely(newskb == NULL)) {
|
|
+ PRINTM(ERROR, "Tx: Cannot allocate skb\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ kfree_skb(skb);
|
|
+ skb = newskb;
|
|
+ PRINTM(INFO, "new skb headroom %d\n", skb_headroom(skb));
|
|
+ }
|
|
+ /* headptr should be aligned */
|
|
+ headptr = skb->data - sizeof(TxPD) - INTF_HEADER_LEN;
|
|
+ headptr = (u8 *) ((u32) headptr & ~((u32) (HEADER_ALIGNMENT - 1)));
|
|
+
|
|
+ pLocalTxPD = (TxPD *) (headptr + INTF_HEADER_LEN);
|
|
+ memset(pLocalTxPD, 0, sizeof(TxPD));
|
|
+ pLocalTxPD->BssType = PKT_TYPE_MICROAP;
|
|
+ pLocalTxPD->TxPktLength = skb->len;
|
|
+ /* offset of actual data */
|
|
+ pLocalTxPD->TxPktOffset = (long) skb->data - (long) pLocalTxPD;
|
|
+ endian_convert_TxPD(pLocalTxPD);
|
|
+ *(u16 *) & headptr[0] =
|
|
+ uap_cpu_to_le16(skb->len + ((long) skb->data - (long) headptr));
|
|
+ *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_DAT);
|
|
+ ret =
|
|
+ sbi_host_to_card(priv, headptr,
|
|
+ skb->len + ((long) skb->data - (long) headptr));
|
|
+ if (ret) {
|
|
+ PRINTM(ERROR, "uap_process_tx Error: sbi_host_to_card failed: 0x%X\n",
|
|
+ ret);
|
|
+ Adapter->dbg.num_tx_host_to_card_failure++;
|
|
+ goto done;
|
|
+ }
|
|
+ PRINTM(DATA, "Data => FW\n");
|
|
+ DBG_HEXDUMP(DAT_D, "Tx", headptr,
|
|
+ MIN(skb->len + sizeof(TxPD), DATA_DUMP_LEN));
|
|
+ done:
|
|
+ /* Freed skb */
|
|
+ kfree_skb(skb);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function initializes the adapter structure
|
|
+ * and set default value to the member of adapter.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_init_sw(uap_private * priv)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!(Adapter->CmdBuf = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
|
|
+ PRINTM(INFO, "Failed to allocate command buffer!\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ Adapter->cmd_pending = FALSE;
|
|
+ Adapter->CmdWaitQWoken = FALSE;
|
|
+ Adapter->ps_state = PS_STATE_AWAKE;
|
|
+ Adapter->WakeupTries = 0;
|
|
+
|
|
+ memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
|
|
+ /** SDIO header */
|
|
+ Adapter->PSConfirmSleep.SDLen =
|
|
+ uap_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
|
|
+ Adapter->PSConfirmSleep.SDType = uap_cpu_to_le16(MV_TYPE_CMD);
|
|
+ Adapter->PSConfirmSleep.SeqNum = 0;
|
|
+ Adapter->PSConfirmSleep.Command = uap_cpu_to_le16(HOST_CMD_SLEEP_CONFIRM);
|
|
+ Adapter->PSConfirmSleep.Size = uap_cpu_to_le16(sizeof(HostCmd_DS_GEN));
|
|
+ Adapter->PSConfirmSleep.Result = 0;
|
|
+
|
|
+ init_waitqueue_head(&Adapter->cmdwait_q);
|
|
+ OS_INIT_SEMAPHORE(&Adapter->CmdSem);
|
|
+
|
|
+ skb_queue_head_init(&Adapter->tx_queue);
|
|
+ skb_queue_head_init(&Adapter->cmd_queue);
|
|
+
|
|
+ /* Status variable */
|
|
+ Adapter->HardwareStatus = HWInitializing;
|
|
+
|
|
+ /* PnP support */
|
|
+ Adapter->SurpriseRemoved = FALSE;
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
|
|
+ Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
|
|
+ NL_MULTICAST_GROUP, NULL,
|
|
+ THIS_MODULE);
|
|
+#else
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
|
+ Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
|
|
+ NL_MULTICAST_GROUP, NULL, NULL,
|
|
+ THIS_MODULE);
|
|
+#else
|
|
+ Adapter->nl_sk = netlink_kernel_create(&init_net, NETLINK_MARVELL,
|
|
+ NL_MULTICAST_GROUP, NULL, NULL,
|
|
+ THIS_MODULE);
|
|
+#endif
|
|
+#endif
|
|
+ if (!Adapter->nl_sk) {
|
|
+ PRINTM(ERROR,
|
|
+ "Could not initialize netlink event passing mechanism!\n");
|
|
+ }
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function sends FUNC_INIT command to firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
|
|
+ */
|
|
+static int
|
|
+uap_func_init(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_GEN *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+ ENTER();
|
|
+ if (Adapter->HardwareStatus != HWReady) {
|
|
+ PRINTM(ERROR, "uap_func_init:Hardware is not ready!\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ CmdSize = sizeof(HostCmd_DS_GEN);
|
|
+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_INIT);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ PRINTM(CMND, "HostCmd_CMD_FUNC_INIT\n");
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_INIT\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function sends FUNC_SHUTDOWN command to firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
|
|
+ */
|
|
+static int __exit
|
|
+uap_func_shutdown(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_GEN *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+ ENTER();
|
|
+ if (Adapter->HardwareStatus != HWReady) {
|
|
+ PRINTM(ERROR, "uap_func_shutdown:Hardware is not ready!\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ CmdSize = sizeof(HostCmd_DS_GEN);
|
|
+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_SHUTDOWN);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ PRINTM(CMND, "HostCmd_CMD_FUNC_SHUTDOWN\n");
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_SHUTDOWN\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function initializes firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_init_fw(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ ENTER();
|
|
+ sbi_disable_host_int(priv);
|
|
+ /* Check if firmware is already running */
|
|
+ if (sbi_check_fw_status(priv, 1) == UAP_STATUS_SUCCESS) {
|
|
+ PRINTM(MSG, "UAP FW already running! Skip FW download\n");
|
|
+ } else {
|
|
+ if ((ret = request_firmware(&priv->fw_helper, helper_name,
|
|
+ priv->hotplug_device)) < 0) {
|
|
+ PRINTM(FATAL,
|
|
+ "request_firmware() failed (helper), error code = %#x\n",
|
|
+ ret);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* Download the helper */
|
|
+ ret = sbi_prog_helper(priv);
|
|
+
|
|
+ if (ret) {
|
|
+ PRINTM(FATAL,
|
|
+ "Bootloader in invalid state! Helper download failed!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ if ((ret = request_firmware(&priv->firmware, fw_name,
|
|
+ priv->hotplug_device)) < 0) {
|
|
+ PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* Download the main firmware via the helper firmware */
|
|
+ if (sbi_prog_fw_w_helper(priv)) {
|
|
+ PRINTM(FATAL, "UAP FW download failed!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ /* Check if the firmware is downloaded successfully or not */
|
|
+ if (sbi_check_fw_status(priv, MAX_FIRMWARE_POLL_TRIES) ==
|
|
+ UAP_STATUS_FAILURE) {
|
|
+ PRINTM(FATAL, "FW failed to be active in time!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ PRINTM(MSG, "UAP FW is active\n");
|
|
+ }
|
|
+ sbi_enable_host_int(priv);
|
|
+ priv->adapter->HardwareStatus = HWReady;
|
|
+ if (uap_func_init(priv) != UAP_STATUS_SUCCESS) {
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ done:
|
|
+ if (priv->fw_helper)
|
|
+ release_firmware(priv->fw_helper);
|
|
+ if (priv->firmware)
|
|
+ release_firmware(priv->firmware);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function frees the structure of adapter
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return n/a
|
|
+ */
|
|
+static void
|
|
+uap_free_adapter(uap_private * priv)
|
|
+{
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (Adapter) {
|
|
+ if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
|
|
+ sock_release((Adapter->nl_sk)->sk_socket);
|
|
+ Adapter->nl_sk = NULL;
|
|
+ }
|
|
+ if (Adapter->CmdBuf)
|
|
+ kfree(Adapter->CmdBuf);
|
|
+ skb_queue_purge(&priv->adapter->tx_queue);
|
|
+ skb_queue_purge(&priv->adapter->cmd_queue);
|
|
+ /* Free the adapter object itself */
|
|
+ kfree(Adapter);
|
|
+ priv->adapter = NULL;
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles the major job in uap driver.
|
|
+ * it handles the event generated by firmware, rx data received
|
|
+ * from firmware and tx data sent from kernel.
|
|
+ *
|
|
+ * @param data A pointer to uap_thread structure
|
|
+ * @return BT_STATUS_SUCCESS
|
|
+ */
|
|
+static int
|
|
+uap_service_main_thread(void *data)
|
|
+{
|
|
+ uap_thread *thread = data;
|
|
+ uap_private *priv = thread->priv;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ wait_queue_t wait;
|
|
+ u8 ireg = 0;
|
|
+ struct sk_buff *skb;
|
|
+ ENTER();
|
|
+ uap_activate_thread(thread);
|
|
+ init_waitqueue_entry(&wait, current);
|
|
+ current->flags |= PF_NOFREEZE;
|
|
+
|
|
+ for (;;) {
|
|
+ add_wait_queue(&thread->waitQ, &wait);
|
|
+ OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
|
|
+ if ((Adapter->WakeupTries) ||
|
|
+ (!Adapter->IntCounter && Adapter->ps_state == PS_STATE_PRE_SLEEP) ||
|
|
+ (!priv->adapter->IntCounter
|
|
+ && (priv->uap_dev.data_sent ||
|
|
+ skb_queue_empty(&priv->adapter->tx_queue))
|
|
+ && (priv->uap_dev.cmd_sent || Adapter->cmd_pending ||
|
|
+ skb_queue_empty(&priv->adapter->cmd_queue))
|
|
+ )) {
|
|
+ PRINTM(INFO, "Main: Thread sleeping...\n");
|
|
+ schedule();
|
|
+ }
|
|
+ OS_SET_THREAD_STATE(TASK_RUNNING);
|
|
+ remove_wait_queue(&thread->waitQ, &wait);
|
|
+ if (kthread_should_stop() || Adapter->SurpriseRemoved) {
|
|
+ PRINTM(INFO, "main-thread: break from main thread: "
|
|
+ "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
|
|
+ /* Cancel pending command */
|
|
+ if (Adapter->cmd_pending == TRUE) {
|
|
+ /* Wake up cmd Q */
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "Main: Thread waking up...\n");
|
|
+ if (priv->adapter->IntCounter) {
|
|
+ OS_INT_DISABLE;
|
|
+ Adapter->IntCounter = 0;
|
|
+ OS_INT_RESTORE;
|
|
+ sbi_get_int_status(priv, &ireg);
|
|
+ } else if ((priv->adapter->ps_state == PS_STATE_SLEEP) &&
|
|
+ (!skb_queue_empty(&priv->adapter->cmd_queue) ||
|
|
+ !skb_queue_empty(&priv->adapter->tx_queue))) {
|
|
+ priv->adapter->WakeupTries++;
|
|
+ PRINTM(CMND, "%lu : Wakeup device...\n", os_time_get());
|
|
+ sbi_wakeup_firmware(priv);
|
|
+ continue;
|
|
+ }
|
|
+ if (Adapter->ps_state == PS_STATE_PRE_SLEEP)
|
|
+ uap_ps_cond_check(priv);
|
|
+
|
|
+ /* The PS state is changed during processing of Sleep Request event
|
|
+ above */
|
|
+ if ((Adapter->ps_state == PS_STATE_SLEEP) ||
|
|
+ (Adapter->ps_state == PS_STATE_PRE_SLEEP))
|
|
+ continue;
|
|
+ /* Execute the next command */
|
|
+ if (!priv->uap_dev.cmd_sent && !Adapter->cmd_pending &&
|
|
+ (Adapter->HardwareStatus == HWReady)) {
|
|
+ if (!skb_queue_empty(&priv->adapter->cmd_queue)) {
|
|
+ skb = skb_dequeue(&priv->adapter->cmd_queue);
|
|
+ if (skb) {
|
|
+ Adapter->CmdSize = 0;
|
|
+ Adapter->cmd_pending = TRUE;
|
|
+ Adapter->cmd_wait_option = skb->cb[0];
|
|
+ if (sbi_host_to_card(priv, skb->data, skb->len)) {
|
|
+ PRINTM(ERROR, "Cmd:sbi_host_to_card failed!\n");
|
|
+ Adapter->cmd_pending = FALSE;
|
|
+ Adapter->dbg.num_cmd_host_to_card_failure++;
|
|
+ /* Wake up cmd Q */
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ } else {
|
|
+ if (Adapter->cmd_wait_option ==
|
|
+ HostCmd_OPTION_WAITFORSEND) {
|
|
+ /* Wake up cmd Q */
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ Adapter->cmd_wait_option = FALSE;
|
|
+ }
|
|
+ }
|
|
+ kfree_skb(skb);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (!priv->uap_dev.data_sent && (Adapter->HardwareStatus == HWReady)) {
|
|
+ if (!skb_queue_empty(&priv->adapter->tx_queue)) {
|
|
+ skb = skb_dequeue(&priv->adapter->tx_queue);
|
|
+ if (skb) {
|
|
+ if (uap_process_tx(priv, skb)) {
|
|
+ priv->stats.tx_dropped++;
|
|
+ priv->stats.tx_errors++;
|
|
+ os_start_queue(priv);
|
|
+ } else {
|
|
+ priv->stats.tx_packets++;
|
|
+ priv->stats.tx_bytes += skb->len;
|
|
+ }
|
|
+
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ uap_deactivate_thread(thread);
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief uap hostcmd ioctl handler
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @param req A pointer to ifreq structure
|
|
+ * @return UAP_STATUS_SUCCESS --success, otherwise fail
|
|
+ */
|
|
+/********* format of ifr_data *************/
|
|
+/* buf_len + Hostcmd_body */
|
|
+/* buf_len: 4 bytes */
|
|
+/* the length of the buf which */
|
|
+/* can be used to return data */
|
|
+/* to application */
|
|
+/* Hostcmd_body */
|
|
+/*******************************************/
|
|
+static int
|
|
+uap_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
|
|
+{
|
|
+ u32 buf_len;
|
|
+ HostCmd_HEADER head;
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* Sanity check */
|
|
+ if (req->ifr_data == NULL) {
|
|
+ PRINTM(ERROR, "uap_hostcmd_ioctl() corrupt data\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
|
|
+ PRINTM(ERROR, "Copy from user failed\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ memset(&head, 0, sizeof(HostCmd_HEADER));
|
|
+ /* Get the command size from user space */
|
|
+ if (copy_from_user
|
|
+ (&head, req->ifr_data + sizeof(buf_len), sizeof(HostCmd_HEADER))) {
|
|
+ PRINTM(ERROR, "Copy from user failed\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ head.Size = uap_le16_to_cpu(head.Size);
|
|
+ if (head.Size > MRVDRV_SIZE_OF_CMD_BUFFER) {
|
|
+ PRINTM(ERROR, "CmdSize too big=%d\n", head.Size);
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ PRINTM(CMND, "ioctl: hostcmd=%x, size=%d,buf_len=%d\n", head.Command,
|
|
+ head.Size, buf_len);
|
|
+ skb = dev_alloc_skb(head.Size + INTF_HEADER_LEN);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ LEAVE();
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Get the command from user space */
|
|
+ if (copy_from_user
|
|
+ (skb->data + INTF_HEADER_LEN, req->ifr_data + sizeof(buf_len),
|
|
+ head.Size)) {
|
|
+ PRINTM(ERROR, "Copy from user failed\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ skb_put(skb, head.Size + INTF_HEADER_LEN);
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ if (!Adapter->CmdSize) {
|
|
+ PRINTM(ERROR, "Cmd Size is 0\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ if (Adapter->CmdSize > buf_len) {
|
|
+ PRINTM(ERROR, "buf_len is too small\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ /* Copy to user */
|
|
+ if (copy_to_user
|
|
+ (req->ifr_data + sizeof(buf_len), Adapter->CmdBuf, Adapter->CmdSize)) {
|
|
+ PRINTM(ERROR, "Copy to user failed!\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief uap power mode ioctl handler
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @param req A pointer to ifreq structure
|
|
+ * @return UAP_STATUS_SUCCESS --success, otherwise fail
|
|
+ */
|
|
+static int
|
|
+uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
|
|
+{
|
|
+ ps_mgmt pm_cfg;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb = NULL;
|
|
+ HostCmd_DS_COMMAND *cmd;
|
|
+ u32 CmdSize;
|
|
+ u8 *tlv = NULL;
|
|
+ MrvlIEtypes_sleep_param_t *sleep_tlv = NULL;
|
|
+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = NULL;
|
|
+ u16 tlv_buf_left = 0;
|
|
+ MrvlIEtypesHeader_t *tlvbuf = NULL;
|
|
+ u16 tlv_type = 0;
|
|
+ u16 tlv_len = 0;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* Sanity check */
|
|
+ if (req->ifr_data == NULL) {
|
|
+ PRINTM(ERROR, "uap_power_mode_ioctl() corrupt data\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ memset(&pm_cfg, 0, sizeof(ps_mgmt));
|
|
+ if (copy_from_user(&pm_cfg, req->ifr_data, sizeof(ps_mgmt))) {
|
|
+ PRINTM(ERROR, "Copy from user failed\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ PRINTM(CMND,
|
|
+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
|
|
+ "inact_to=%d min_awake=%d max_awake=%d\n", pm_cfg.flags,
|
|
+ (int) pm_cfg.ps_mode, (int) pm_cfg.sleep_param.ctrl_bitmap,
|
|
+ (int) pm_cfg.sleep_param.min_sleep,
|
|
+ (int) pm_cfg.sleep_param.max_sleep,
|
|
+ (int) pm_cfg.inact_param.inactivity_to,
|
|
+ (int) pm_cfg.inact_param.min_awake,
|
|
+ (int) pm_cfg.inact_param.max_awake);
|
|
+
|
|
+ if (pm_cfg.
|
|
+ flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
|
|
+ PS_FLAG_INACT_SLEEP_PARAM)) {
|
|
+ PRINTM(ERROR, "Invalid parameter: flags = 0x%x\n", pm_cfg.flags);
|
|
+ ret = -EINVAL;
|
|
+ goto done;
|
|
+ }
|
|
+ if (pm_cfg.ps_mode > PS_MODE_INACTIVITY) {
|
|
+ PRINTM(ERROR, "Invalid parameter: ps_mode = %d\n", (int) pm_cfg.flags);
|
|
+ ret = -EINVAL;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(INFO, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ CmdSize = S_DS_GEN + sizeof(HostCmd_DS_POWER_MGMT_EXT);
|
|
+
|
|
+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HOST_CMD_POWER_MGMT_EXT);
|
|
+ if (!pm_cfg.flags) {
|
|
+ cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_GET);
|
|
+ } else {
|
|
+ cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_SET);
|
|
+ cmd->params.pm_cfg.power_mode = uap_cpu_to_le16(pm_cfg.ps_mode);
|
|
+ tlv = (u8 *) & cmd->params.pm_cfg + sizeof(HostCmd_DS_POWER_MGMT_EXT);
|
|
+
|
|
+ if ((pm_cfg.ps_mode) && (pm_cfg.flags & PS_FLAG_SLEEP_PARAM)) {
|
|
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
|
|
+ sleep_tlv->header.Type = uap_cpu_to_le16(TLV_TYPE_AP_SLEEP_PARAM);
|
|
+ sleep_tlv->header.Len =
|
|
+ uap_cpu_to_le16(sizeof(MrvlIEtypes_sleep_param_t) -
|
|
+ sizeof(MrvlIEtypesHeader_t));
|
|
+ sleep_tlv->ctrl_bitmap =
|
|
+ uap_cpu_to_le32(pm_cfg.sleep_param.ctrl_bitmap);
|
|
+ sleep_tlv->min_sleep =
|
|
+ uap_cpu_to_le32(pm_cfg.sleep_param.min_sleep);
|
|
+ sleep_tlv->max_sleep =
|
|
+ uap_cpu_to_le32(pm_cfg.sleep_param.max_sleep);
|
|
+ CmdSize += sizeof(MrvlIEtypes_sleep_param_t);
|
|
+ tlv += sizeof(MrvlIEtypes_sleep_param_t);
|
|
+ }
|
|
+ if ((pm_cfg.ps_mode == PS_MODE_INACTIVITY) &&
|
|
+ (pm_cfg.flags & PS_FLAG_INACT_SLEEP_PARAM)) {
|
|
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
|
|
+ inact_tlv->header.Type =
|
|
+ uap_cpu_to_le16(TLV_TYPE_AP_INACT_SLEEP_PARAM);
|
|
+ inact_tlv->header.Len =
|
|
+ uap_cpu_to_le16(sizeof(MrvlIEtypes_inact_sleep_param_t) -
|
|
+ sizeof(MrvlIEtypesHeader_t));
|
|
+ inact_tlv->inactivity_to =
|
|
+ uap_cpu_to_le32(pm_cfg.inact_param.inactivity_to);
|
|
+ inact_tlv->min_awake =
|
|
+ uap_cpu_to_le32(pm_cfg.inact_param.min_awake);
|
|
+ inact_tlv->max_awake =
|
|
+ uap_cpu_to_le32(pm_cfg.inact_param.max_awake);
|
|
+ CmdSize += sizeof(MrvlIEtypes_inact_sleep_param_t);
|
|
+ tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
|
|
+ }
|
|
+ }
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd POWER_MODE\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ if (!Adapter->CmdSize) {
|
|
+ PRINTM(ERROR, "Cmd Size is 0\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
|
|
+ cmd->Result = uap_le16_to_cpu(cmd->Result);
|
|
+ if (cmd->Result != UAP_STATUS_SUCCESS) {
|
|
+ PRINTM(ERROR, "HOST_CMD_APCMD_POWER_MODE fail=%x\n", cmd->Result);
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ if (pm_cfg.flags) {
|
|
+ Adapter->psmode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
|
|
+ } else {
|
|
+ pm_cfg.flags = PS_FLAG_PS_MODE;
|
|
+ pm_cfg.ps_mode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
|
|
+ tlv_buf_left =
|
|
+ cmd->Size - (sizeof(HostCmd_DS_POWER_MGMT_EXT) + S_DS_GEN);
|
|
+ tlvbuf =
|
|
+ (MrvlIEtypesHeader_t *) ((u8 *) & cmd->params.pm_cfg +
|
|
+ sizeof(HostCmd_DS_POWER_MGMT_EXT));
|
|
+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
|
|
+ tlv_type = uap_le16_to_cpu(tlvbuf->Type);
|
|
+ tlv_len = uap_le16_to_cpu(tlvbuf->Len);
|
|
+ switch (tlv_type) {
|
|
+ case TLV_TYPE_AP_SLEEP_PARAM:
|
|
+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlvbuf;
|
|
+ pm_cfg.flags |= PS_FLAG_SLEEP_PARAM;
|
|
+ pm_cfg.sleep_param.ctrl_bitmap =
|
|
+ uap_le32_to_cpu(sleep_tlv->ctrl_bitmap);
|
|
+ pm_cfg.sleep_param.min_sleep =
|
|
+ uap_le32_to_cpu(sleep_tlv->min_sleep);
|
|
+ pm_cfg.sleep_param.max_sleep =
|
|
+ uap_le32_to_cpu(sleep_tlv->max_sleep);
|
|
+ break;
|
|
+ case TLV_TYPE_AP_INACT_SLEEP_PARAM:
|
|
+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlvbuf;
|
|
+ pm_cfg.flags |= PS_FLAG_INACT_SLEEP_PARAM;
|
|
+ pm_cfg.inact_param.inactivity_to =
|
|
+ uap_le32_to_cpu(inact_tlv->inactivity_to);
|
|
+ pm_cfg.inact_param.min_awake =
|
|
+ uap_le32_to_cpu(inact_tlv->min_awake);
|
|
+ pm_cfg.inact_param.max_awake =
|
|
+ uap_le32_to_cpu(inact_tlv->max_awake);
|
|
+ break;
|
|
+ }
|
|
+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
|
|
+ tlvbuf =
|
|
+ (MrvlIEtypesHeader_t *) ((u8 *) tlvbuf + tlv_len +
|
|
+ sizeof(MrvlIEtypesHeader_t));
|
|
+ }
|
|
+ /* Copy to user */
|
|
+ if (copy_to_user(req->ifr_data, &pm_cfg, sizeof(ps_mgmt))) {
|
|
+ PRINTM(ERROR, "Copy to user failed!\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function send bss_stop command to firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
|
|
+ */
|
|
+static int
|
|
+uap_bss_stop(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_GEN *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+ ENTER();
|
|
+ if (Adapter->HardwareStatus != HWReady) {
|
|
+ PRINTM(ERROR, "uap_bss_stop:Hardware is not ready!\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ CmdSize = sizeof(HostCmd_DS_GEN);
|
|
+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_BSS_STOP);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ PRINTM(CMND, "APCMD_BSS_STOP\n");
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd BSS_STOP\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/********************************************************
|
|
+ Global Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief This function send soft_reset command to firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
|
|
+ */
|
|
+int
|
|
+uap_soft_reset(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_GEN *cmd;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+ ENTER();
|
|
+ ret = uap_bss_stop(priv);
|
|
+ if (ret != UAP_STATUS_SUCCESS)
|
|
+ goto done;
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+ CmdSize = sizeof(HostCmd_DS_GEN);
|
|
+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SOFT_RESET);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ PRINTM(CMND, "APCMD_SOFT_RESET\n");
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORSEND)) {
|
|
+ PRINTM(ERROR, "Fail to process cmd SOFT_RESET\n");
|
|
+ ret = -EFAULT;
|
|
+ goto done;
|
|
+ }
|
|
+ Adapter->SurpriseRemoved = TRUE;
|
|
+ /* delay to allow hardware complete reset */
|
|
+ os_sched_timeout(5);
|
|
+ if (priv->MediaConnected == TRUE) {
|
|
+ os_stop_queue(priv);
|
|
+ os_carrier_off(priv);
|
|
+ priv->MediaConnected = FALSE;
|
|
+ }
|
|
+ Adapter->CmdSize = 0;
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ skb_queue_purge(&priv->adapter->tx_queue);
|
|
+ skb_queue_purge(&priv->adapter->cmd_queue);
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function processes received packet and forwards it
|
|
+ * to kernel/upper layer
|
|
+ *
|
|
+ * @param priv A pointer to uap_private
|
|
+ * @param skb A pointer to skb which includes the received packet
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+uap_process_rx_packet(uap_private * priv, struct sk_buff *skb)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ RxPD *pRxPD;
|
|
+ ENTER();
|
|
+ priv->adapter->ps_state = PS_STATE_AWAKE;
|
|
+ pRxPD = (RxPD *) skb->data;
|
|
+ endian_convert_RxPD(pRxPD);
|
|
+ DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
|
|
+ skb_pull(skb, pRxPD->RxPktOffset);
|
|
+ priv->stats.rx_packets++;
|
|
+ priv->stats.rx_bytes += skb->len;
|
|
+ os_upload_rx_packet(priv, skb);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function opens the network device
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+static int
|
|
+uap_open(struct net_device *dev)
|
|
+{
|
|
+ uap_private *priv = (uap_private *) (uap_private *) netdev_priv(dev);
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ int i = 0;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* On some systems the device open handler will be called before HW ready. */
|
|
+ /* Use the following flag check and wait function to work around the issue. */
|
|
+ while ((Adapter->HardwareStatus != HWReady) &&
|
|
+ (i < MAX_WAIT_DEVICE_READY_COUNT)) {
|
|
+ i++;
|
|
+ os_sched_timeout(100);
|
|
+ }
|
|
+ if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
|
|
+ PRINTM(FATAL, "HW not ready, uap_open() return failure\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ if (MODULE_GET == 0)
|
|
+ return UAP_STATUS_FAILURE;
|
|
+
|
|
+ priv->open = TRUE;
|
|
+ if (priv->MediaConnected == TRUE) {
|
|
+ os_carrier_on(priv);
|
|
+ os_start_queue(priv);
|
|
+ } else {
|
|
+ os_stop_queue(priv);
|
|
+ os_carrier_off(priv);
|
|
+ }
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function closes the network device
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+static int
|
|
+uap_close(struct net_device *dev)
|
|
+{
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+
|
|
+ ENTER();
|
|
+ skb_queue_purge(&priv->adapter->tx_queue);
|
|
+ os_stop_queue(priv);
|
|
+ os_carrier_off(priv);
|
|
+
|
|
+ MODULE_PUT;
|
|
+ priv->open = FALSE;
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function returns the network statistics
|
|
+ *
|
|
+ * @param dev A pointer to uap_private structure
|
|
+ * @return A pointer to net_device_stats structure
|
|
+ */
|
|
+static struct net_device_stats *
|
|
+uap_get_stats(struct net_device *dev)
|
|
+{
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+
|
|
+ return &priv->stats;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function sets the MAC address to firmware.
|
|
+ *
|
|
+ * @param dev A pointer to uap_private structure
|
|
+ * @param addr MAC address to set
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_set_mac_address(struct net_device *dev, void *addr)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+ struct sockaddr *pHwAddr = (struct sockaddr *) addr;
|
|
+ u32 CmdSize;
|
|
+ HostCmd_DS_COMMAND *cmd;
|
|
+ MrvlIEtypes_MacAddr_t *pMacAddrTlv;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* Dump MAC address */
|
|
+ DBG_HEXDUMP(CMD_D, "Original MAC addr", dev->dev_addr, ETH_ALEN);
|
|
+ DBG_HEXDUMP(CMD_D, "New MAC addr", pHwAddr->sa_data, ETH_ALEN);
|
|
+ if (priv->open && (priv->MediaConnected == TRUE)) {
|
|
+ os_carrier_on(priv);
|
|
+ os_start_queue(priv);
|
|
+ }
|
|
+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
+ if (!skb) {
|
|
+ PRINTM(ERROR, "No free skb\n");
|
|
+ LEAVE();
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ CmdSize =
|
|
+ S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
|
|
+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
|
|
+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
|
|
+ cmd->Size = uap_cpu_to_le16(CmdSize);
|
|
+ cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_SET);
|
|
+ pMacAddrTlv =
|
|
+ (MrvlIEtypes_MacAddr_t *) ((u8 *) cmd + S_DS_GEN +
|
|
+ sizeof(HostCmd_SYS_CONFIG));
|
|
+ pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
|
|
+ pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
|
|
+ memcpy(pMacAddrTlv->ApMacAddr, pHwAddr->sa_data, ETH_ALEN);
|
|
+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
|
|
+ PRINTM(CMND, "set_mac_address\n");
|
|
+ if (UAP_STATUS_SUCCESS !=
|
|
+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
|
|
+ PRINTM(ERROR, "Fail to set mac address\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ if (!Adapter->CmdSize) {
|
|
+ PRINTM(ERROR, "Cmd Size is 0\n");
|
|
+ LEAVE();
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
|
|
+ cmd->Result = uap_cpu_to_le16(cmd->Result);
|
|
+ if (cmd->Result != UAP_STATUS_SUCCESS) {
|
|
+ PRINTM(ERROR, "set mac addrress fail,cmd result=%x\n", cmd->Result);
|
|
+ ret = -EFAULT;
|
|
+ } else
|
|
+ memcpy(dev->dev_addr, pHwAddr->sa_data, ETH_ALEN);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function sets multicast addresses to firmware
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @return n/a
|
|
+ */
|
|
+static void
|
|
+uap_set_multicast_list(struct net_device *dev)
|
|
+{
|
|
+ ENTER();
|
|
+#warning uap_set_multicast_list not implemented. Expect problems with IPv6.
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles the timeout of packet
|
|
+ * transmission
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @return n/a
|
|
+ */
|
|
+static void
|
|
+uap_tx_timeout(struct net_device *dev)
|
|
+{
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ PRINTM(DATA, "Tx timeout\n");
|
|
+ UpdateTransStart(dev);
|
|
+ priv->num_tx_timeout++;
|
|
+ priv->adapter->IntCounter++;
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles packet transmission
|
|
+ *
|
|
+ * @param skb A pointer to sk_buff structure
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
+{
|
|
+ uap_private *priv = (uap_private *) netdev_priv(dev);
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+ PRINTM(DATA, "Data <= kernel\n");
|
|
+ DBG_HEXDUMP(DAT_D, "Tx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
|
|
+ /* skb sanity check */
|
|
+ if (!skb->len || (skb->len > MRVDRV_MAXIMUM_ETH_PACKET_SIZE)) {
|
|
+ PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
|
|
+ MRVDRV_MAXIMUM_ETH_PACKET_SIZE);
|
|
+ priv->stats.tx_dropped++;
|
|
+ kfree(skb);
|
|
+ goto done;
|
|
+ }
|
|
+ skb_queue_tail(&priv->adapter->tx_queue, skb);
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+ if (skb_queue_len(&priv->adapter->tx_queue) > TX_HIGH_WATERMARK) {
|
|
+ UpdateTransStart(dev);
|
|
+ os_stop_queue(priv);
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief ioctl function - entry point
|
|
+ *
|
|
+ * @param dev A pointer to net_device structure
|
|
+ * @param req A pointer to ifreq structure
|
|
+ * @param cmd command
|
|
+ * @return UAP_STATUS_SUCCESS--success, otherwise fail
|
|
+ */
|
|
+static int
|
|
+uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ PRINTM(CMND, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
|
|
+
|
|
+ switch (cmd) {
|
|
+ case UAPHOSTCMD:
|
|
+ ret = uap_hostcmd_ioctl(dev, req);
|
|
+ break;
|
|
+ case UAP_POWER_MODE:
|
|
+ ret = uap_power_mode_ioctl(dev, req);
|
|
+ break;
|
|
+ default:
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles events generated by firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param payload A pointer to payload buffer
|
|
+ * @param len Length of the payload
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+uap_process_event(uap_private * priv, u8 * payload, uint len)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ uap_adapter *Adapter = priv->adapter;
|
|
+ struct sk_buff *skb = NULL;
|
|
+ struct nlmsghdr *nlh = NULL;
|
|
+ struct sock *sk = Adapter->nl_sk;
|
|
+ AP_Event *pEvent;
|
|
+
|
|
+ ENTER();
|
|
+ Adapter->ps_state = PS_STATE_AWAKE;
|
|
+ if (len > NL_MAX_PAYLOAD) {
|
|
+ PRINTM(ERROR, "event size is too big!!! len=%d\n", len);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ pEvent = (AP_Event *) payload;
|
|
+ PRINTM(CMND, "Event: %d\n", pEvent->EventId);
|
|
+ switch (pEvent->EventId) {
|
|
+ case MICRO_AP_EV_ID_BSS_START:
|
|
+ memcpy(priv->uap_dev.netdev->dev_addr, pEvent->MacAddr, ETH_ALEN);
|
|
+ DBG_HEXDUMP(CMD_D, "BSS MAC addr", priv->uap_dev.netdev->dev_addr,
|
|
+ ETH_ALEN);
|
|
+ break;
|
|
+ case MICRO_AP_EV_BSS_ACTIVE:
|
|
+ // carrier on
|
|
+ priv->MediaConnected = TRUE;
|
|
+ os_carrier_on(priv);
|
|
+ os_start_queue(priv);
|
|
+ break;
|
|
+ case MICRO_AP_EV_BSS_IDLE:
|
|
+ os_stop_queue(priv);
|
|
+ os_carrier_off(priv);
|
|
+ priv->MediaConnected = FALSE;
|
|
+ break;
|
|
+ case EVENT_PS_AWAKE:
|
|
+ PRINTM(CMND, "UAP: PS_AWAKE\n");
|
|
+ Adapter->ps_state = PS_STATE_AWAKE;
|
|
+ Adapter->WakeupTries = 0;
|
|
+ break;
|
|
+ case EVENT_PS_SLEEP:
|
|
+ PRINTM(CMND, "UAP: PS_SLEEP\n");
|
|
+ Adapter->ps_state = PS_STATE_PRE_SLEEP;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ if ((pEvent->EventId == EVENT_PS_AWAKE) ||
|
|
+ (pEvent->EventId == EVENT_PS_SLEEP))
|
|
+ goto done;
|
|
+ if (sk) {
|
|
+ /* Allocate skb */
|
|
+ if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
|
|
+ PRINTM(ERROR, "Could not allocate skb for netlink.\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ nlh = (struct nlmsghdr *) skb->data;
|
|
+ nlh->nlmsg_len = NLMSG_SPACE(len);
|
|
+
|
|
+ /* From kernel */
|
|
+ nlh->nlmsg_pid = 0;
|
|
+ nlh->nlmsg_flags = 0;
|
|
+
|
|
+ /* Data */
|
|
+ skb_put(skb, nlh->nlmsg_len);
|
|
+ memcpy(NLMSG_DATA(nlh), payload, len);
|
|
+
|
|
+ /* From Kernel */
|
|
+ NETLINK_CB(skb).pid = 0;
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
|
+ /* Multicast message */
|
|
+ NETLINK_CB(skb).dst_pid = 0;
|
|
+#endif
|
|
+
|
|
+ /* Multicast group number */
|
|
+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
|
|
+
|
|
+ /* Send message */
|
|
+ netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_KERNEL);
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ } else {
|
|
+ PRINTM(ERROR, "Could not send event through NETLINK. Link down.\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ }
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles the interrupt. it will change PS
|
|
+ * state if applicable. it will wake up main_thread to handle
|
|
+ * the interrupt event as well.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return n/a
|
|
+ */
|
|
+void
|
|
+uap_interrupt(uap_private * priv)
|
|
+{
|
|
+ ENTER();
|
|
+ priv->adapter->IntCounter++;
|
|
+ priv->adapter->WakeupTries = 0;
|
|
+ PRINTM(INFO, "*\n");
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+
|
|
+ LEAVE();
|
|
+
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
|
|
+/** Network device handlers */
|
|
+static const struct net_device_ops uap_netdev_ops = {
|
|
+ .ndo_open = uap_open,
|
|
+ .ndo_start_xmit = uap_hard_start_xmit,
|
|
+ .ndo_stop = uap_close,
|
|
+ .ndo_do_ioctl = uap_do_ioctl,
|
|
+ .ndo_set_mac_address = uap_set_mac_address,
|
|
+ .ndo_tx_timeout = uap_tx_timeout,
|
|
+ .ndo_get_stats = uap_get_stats,
|
|
+ .ndo_set_multicast_list = uap_set_multicast_list,
|
|
+};
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * @brief This function adds the card. it will probe the
|
|
+ * card, allocate the uap_priv and initialize the device.
|
|
+ *
|
|
+ * @param card A pointer to card
|
|
+ * @return A pointer to uap_private structure
|
|
+ */
|
|
+uap_private *
|
|
+uap_add_card(void *card)
|
|
+{
|
|
+ struct net_device *dev = NULL;
|
|
+ uap_private *priv = NULL;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
|
|
+ goto exit_sem_err;
|
|
+
|
|
+ /* Allocate an Ethernet device */
|
|
+ if (!(dev = alloc_etherdev(sizeof(uap_private)))) {
|
|
+ PRINTM(FATAL, "Init ethernet device failed!\n");
|
|
+ goto error;
|
|
+ }
|
|
+ priv = (uap_private *) netdev_priv(dev);
|
|
+
|
|
+ /* Allocate name */
|
|
+ if (dev_alloc_name(dev, "uap%d") < 0) {
|
|
+ PRINTM(ERROR, "Could not allocate device name!\n");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Allocate buffer for uap_adapter */
|
|
+ if (!(priv->adapter = kmalloc(sizeof(uap_adapter), GFP_KERNEL))) {
|
|
+ PRINTM(FATAL, "Allocate buffer for uap_adapter failed!\n");
|
|
+ goto error;
|
|
+ }
|
|
+ memset(priv->adapter, 0, sizeof(uap_adapter));
|
|
+
|
|
+ priv->uap_dev.netdev = dev;
|
|
+ priv->uap_dev.card = card;
|
|
+ priv->MediaConnected = FALSE;
|
|
+ uappriv = priv;
|
|
+ ((struct sdio_mmc_card *) card)->priv = priv;
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
|
+ SET_MODULE_OWNER(dev);
|
|
+#endif
|
|
+
|
|
+ /* Setup the OS Interface to our functions */
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
|
|
+ dev->open = uap_open;
|
|
+ dev->stop = uap_close;
|
|
+ dev->hard_start_xmit = uap_hard_start_xmit;
|
|
+ dev->tx_timeout = uap_tx_timeout;
|
|
+ dev->get_stats = uap_get_stats;
|
|
+ dev->do_ioctl = uap_do_ioctl;
|
|
+ dev->set_mac_address = uap_set_mac_address;
|
|
+ dev->set_multicast_list = uap_set_multicast_list;
|
|
+#else
|
|
+ dev->netdev_ops = &uap_netdev_ops;
|
|
+#endif
|
|
+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
|
|
+ dev->hard_header_len += sizeof(TxPD) + INTF_HEADER_LEN;
|
|
+ dev->hard_header_len += HEADER_ALIGNMENT;
|
|
+#define NETIF_F_DYNALLOC 16
|
|
+ dev->features |= NETIF_F_DYNALLOC;
|
|
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
|
|
+
|
|
+ /* Init SW */
|
|
+ if (uap_init_sw(priv)) {
|
|
+ PRINTM(FATAL, "Software Init Failed\n");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "Starting kthread...\n");
|
|
+ priv->MainThread.priv = priv;
|
|
+ spin_lock_init(&priv->driver_lock);
|
|
+ uap_create_thread(uap_service_main_thread, &priv->MainThread,
|
|
+ "uap_main_service");
|
|
+ while (priv->MainThread.pid == 0) {
|
|
+ os_sched_timeout(2);
|
|
+ }
|
|
+
|
|
+ /* Register the device */
|
|
+ if (sbi_register_dev(priv) < 0) {
|
|
+ PRINTM(FATAL, "Failed to register uap device!\n");
|
|
+ goto err_registerdev;
|
|
+ }
|
|
+#ifdef FW_DNLD_NEEDED
|
|
+ SET_NETDEV_DEV(dev, priv->hotplug_device);
|
|
+#endif
|
|
+
|
|
+ /* Init FW and HW */
|
|
+ if (uap_init_fw(priv)) {
|
|
+ PRINTM(FATAL, "Firmware Init Failed\n");
|
|
+ goto err_init_fw;
|
|
+ }
|
|
+
|
|
+ priv->uap_dev.cmd_sent = FALSE;
|
|
+ priv->uap_dev.data_sent = FALSE;
|
|
+
|
|
+ /* Get mac address from firmware */
|
|
+ if (uap_get_mac_address(priv)) {
|
|
+ PRINTM(FATAL, "Fail to get mac address\n");
|
|
+ goto err_init_fw;
|
|
+ }
|
|
+ /* Register network device */
|
|
+ if (register_netdev(dev)) {
|
|
+ printk(KERN_ERR "Cannot register network device!\n");
|
|
+ goto err_init_fw;
|
|
+ }
|
|
+#ifdef CONFIG_PROC_FS
|
|
+ uap_proc_entry(priv, dev);
|
|
+ uap_debug_entry(priv, dev);
|
|
+#endif /* CPNFIG_PROC_FS */
|
|
+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
+
|
|
+ LEAVE();
|
|
+ return priv;
|
|
+ err_init_fw:
|
|
+ sbi_unregister_dev(priv);
|
|
+ err_registerdev:
|
|
+ ((struct sdio_mmc_card *) card)->priv = NULL;
|
|
+ /* Stop the thread servicing the interrupts */
|
|
+ priv->adapter->SurpriseRemoved = TRUE;
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+ while (priv->MainThread.pid) {
|
|
+ os_sched_timeout(1);
|
|
+ }
|
|
+ error:
|
|
+ if (dev) {
|
|
+ if (dev->reg_state == NETREG_REGISTERED)
|
|
+ unregister_netdev(dev);
|
|
+ if (priv->adapter)
|
|
+ uap_free_adapter(priv);
|
|
+ free_netdev(dev);
|
|
+ uappriv = NULL;
|
|
+ }
|
|
+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
+ exit_sem_err:
|
|
+ LEAVE();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function removes the card.
|
|
+ *
|
|
+ * @param card A pointer to card
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+int
|
|
+uap_remove_card(void *card)
|
|
+{
|
|
+ uap_private *priv = uappriv;
|
|
+ uap_adapter *Adapter;
|
|
+ struct net_device *dev;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
|
|
+ goto exit_sem_err;
|
|
+
|
|
+ if (!priv || !(Adapter = priv->adapter)) {
|
|
+ goto exit_remove;
|
|
+ }
|
|
+ Adapter->SurpriseRemoved = TRUE;
|
|
+ if (Adapter->cmd_pending == TRUE) {
|
|
+ /* Wake up cmd Q */
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ }
|
|
+ dev = priv->uap_dev.netdev;
|
|
+ if (priv->MediaConnected == TRUE) {
|
|
+ os_stop_queue(priv);
|
|
+ os_carrier_off(priv);
|
|
+ priv->MediaConnected = FALSE;
|
|
+ }
|
|
+ Adapter->CmdSize = 0;
|
|
+ Adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&Adapter->cmdwait_q);
|
|
+ skb_queue_purge(&priv->adapter->tx_queue);
|
|
+ skb_queue_purge(&priv->adapter->cmd_queue);
|
|
+
|
|
+ /* Disable interrupts on the card */
|
|
+ sbi_disable_host_int(priv);
|
|
+ PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
|
|
+ (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
|
|
+ unregister_netdev(dev);
|
|
+ PRINTM(INFO, "Unregister finish\n");
|
|
+ wake_up_interruptible(&priv->MainThread.waitQ);
|
|
+ while (priv->MainThread.pid) {
|
|
+ os_sched_timeout(1);
|
|
+ }
|
|
+
|
|
+ if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
|
|
+ sock_release((Adapter->nl_sk)->sk_socket);
|
|
+ Adapter->nl_sk = NULL;
|
|
+ }
|
|
+#ifdef CONFIG_PROC_FS
|
|
+ uap_debug_remove(priv);
|
|
+ uap_proc_remove(priv);
|
|
+#endif
|
|
+ sbi_unregister_dev(priv);
|
|
+ PRINTM(INFO, "Free Adapter\n");
|
|
+ uap_free_adapter(priv);
|
|
+ priv->uap_dev.netdev = NULL;
|
|
+ free_netdev(dev);
|
|
+ uappriv = NULL;
|
|
+
|
|
+ exit_remove:
|
|
+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
+ exit_sem_err:
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function initializes module.
|
|
+ *
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int __init
|
|
+uap_init_module(void)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ ENTER();
|
|
+
|
|
+ OS_INIT_SEMAPHORE(&AddRemoveCardSem);
|
|
+ ret = sbi_register();
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function cleans module
|
|
+ *
|
|
+ * @return n/a
|
|
+ */
|
|
+static void __exit
|
|
+uap_cleanup_module(void)
|
|
+{
|
|
+ ENTER();
|
|
+
|
|
+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
|
|
+ goto exit_sem_err;
|
|
+
|
|
+ if ((uappriv) && (uappriv->adapter)) {
|
|
+ uap_func_shutdown(uappriv);
|
|
+ }
|
|
+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
|
|
+ exit_sem_err:
|
|
+ sbi_unregister();
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+module_init(uap_init_module);
|
|
+module_exit(uap_cleanup_module);
|
|
+module_param(helper_name, charp, 0);
|
|
+MODULE_PARM_DESC(helper_name, "Helper name");
|
|
+module_param(fw_name, charp, 0);
|
|
+MODULE_PARM_DESC(fw_name, "Firmware name");
|
|
+
|
|
+MODULE_DESCRIPTION("M-UAP Driver");
|
|
+MODULE_AUTHOR("Marvell International Ltd.");
|
|
+MODULE_VERSION(DRIVER_VERSION);
|
|
+MODULE_LICENSE("GPL");
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_proc.c b/drivers/net/wireless/libertas_uap/uap_proc.c
|
|
--- a/drivers/net/wireless/libertas_uap/uap_proc.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_proc.c 2012-05-10 00:59:12.974811500 +0000
|
|
@@ -0,0 +1,296 @@
|
|
+/** @file uap_proc.c
|
|
+ * @brief This file contains functions for proc file.
|
|
+ *
|
|
+ * Copyright (C) 2008-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+#ifdef CONFIG_PROC_FS
|
|
+#include "uap_headers.h"
|
|
+
|
|
+/** /proc directory root */
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
|
|
+#define PROC_DIR NULL
|
|
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
|
|
+#define PROC_DIR &proc_root
|
|
+#else
|
|
+#define PROC_DIR proc_net
|
|
+#endif
|
|
+
|
|
+/********************************************************
|
|
+ Local Variables
|
|
+********************************************************/
|
|
+
|
|
+/********************************************************
|
|
+ Global Variables
|
|
+********************************************************/
|
|
+
|
|
+/********************************************************
|
|
+ Local Functions
|
|
+********************************************************/
|
|
+
|
|
+/**
|
|
+ * @brief proc read function
|
|
+ *
|
|
+ * @param page pointer to buffer
|
|
+ * @param start read data starting position
|
|
+ * @param offset offset
|
|
+ * @param count counter
|
|
+ * @param eof end of file flag
|
|
+ * @param data data to output
|
|
+ * @return number of output data
|
|
+ */
|
|
+static int
|
|
+uap_proc_read(char *page, char **start, off_t offset,
|
|
+ int count, int *eof, void *data)
|
|
+{
|
|
+ int i;
|
|
+ char *p = page;
|
|
+ struct net_device *netdev = data;
|
|
+ struct netdev_hw_addr *ha;
|
|
+ char fmt[64];
|
|
+ uap_private *priv = (uap_private *) netdev_priv(netdev);
|
|
+
|
|
+ if (offset != 0) {
|
|
+ *eof = 1;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ strcpy(fmt, DRIVER_VERSION);
|
|
+
|
|
+ p += sprintf(p, "driver_name = " "\"uap\"\n");
|
|
+ p += sprintf(p, "driver_version = %s-(FP%s)", fmt, FPNUM);
|
|
+ p += sprintf(p, "\nInterfaceName=\"%s\"\n", netdev->name);
|
|
+ p += sprintf(p, "State=\"%s\"\n",
|
|
+ ((priv->MediaConnected ==
|
|
+ FALSE) ? "Disconnected" : "Connected"));
|
|
+ p += sprintf(p, "MACAddress=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
|
|
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
|
|
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
|
|
+ i = 0;
|
|
+ netdev_for_each_mc_addr(ha, netdev) {
|
|
+ ++i;
|
|
+ }
|
|
+ p += sprintf(p, "MCCount=\"%d\"\n", i);
|
|
+
|
|
+ /*
|
|
+ * Put out the multicast list
|
|
+ */
|
|
+ i = 0;
|
|
+ netdev_for_each_mc_addr(ha, netdev) {
|
|
+ p += sprintf(p,
|
|
+ "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
|
|
+ i++,
|
|
+ ha->addr[0], ha->addr[1],
|
|
+ ha->addr[2], ha->addr[3],
|
|
+ ha->addr[4], ha->addr[5]);
|
|
+ }
|
|
+
|
|
+ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
|
|
+ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
|
|
+ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
|
|
+ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
|
|
+ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
|
|
+ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
|
|
+ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
|
|
+ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
|
|
+ p += sprintf(p, "num_tx_timeout = %u\n", priv->num_tx_timeout);
|
|
+ p += sprintf(p, "carrier %s\n",
|
|
+ ((netif_carrier_ok(priv->uap_dev.netdev)) ? "on" : "off"));
|
|
+ p += sprintf(p, "tx queue %s\n",
|
|
+ ((netif_queue_stopped(priv->uap_dev.netdev)) ? "stopped" :
|
|
+ "started"));
|
|
+
|
|
+ exit:
|
|
+ return (p - page);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief hwstatus proc write function
|
|
+ *
|
|
+ * @param f file pointer
|
|
+ * @param buf pointer to data buffer
|
|
+ * @param cnt data number to write
|
|
+ * @param data data to write
|
|
+ * @return number of data
|
|
+ */
|
|
+static int
|
|
+uap_hwstatus_write(struct file *f, const char *buf, unsigned long cnt,
|
|
+ void *data)
|
|
+{
|
|
+ struct net_device *netdev = data;
|
|
+ uap_private *priv = (uap_private *) netdev_priv(netdev);
|
|
+ char databuf[10];
|
|
+ int hwstatus;
|
|
+ MODULE_GET;
|
|
+ if (cnt > 10) {
|
|
+ MODULE_PUT;
|
|
+ return cnt;
|
|
+ }
|
|
+ if (copy_from_user(databuf, buf, cnt)) {
|
|
+ MODULE_PUT;
|
|
+ return 0;
|
|
+ }
|
|
+ hwstatus = string_to_number(databuf);
|
|
+ switch (hwstatus) {
|
|
+ case HWReset:
|
|
+ PRINTM(MSG, "reset hw\n");
|
|
+ uap_soft_reset(priv);
|
|
+ priv->adapter->HardwareStatus = HWReset;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ MODULE_PUT;
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief hwstatus proc read function
|
|
+ *
|
|
+ * @param page pointer to buffer
|
|
+ * @param s read data starting position
|
|
+ * @param off offset
|
|
+ * @param cnt counter
|
|
+ * @param eof end of file flag
|
|
+ * @param data data to output
|
|
+ * @return number of output data
|
|
+ */
|
|
+static int
|
|
+uap_hwstatus_read(char *page, char **s, off_t off, int cnt, int *eof,
|
|
+ void *data)
|
|
+{
|
|
+ char *p = page;
|
|
+ struct net_device *netdev = data;
|
|
+ uap_private *priv = (uap_private *) netdev_priv(netdev);
|
|
+ MODULE_GET;
|
|
+ p += sprintf(p, "%d\n", priv->adapter->HardwareStatus);
|
|
+ MODULE_PUT;
|
|
+ return p - page;
|
|
+}
|
|
+
|
|
+/********************************************************
|
|
+ Global Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief create uap proc file
|
|
+ *
|
|
+ * @param priv pointer uap_private
|
|
+ * @param dev pointer net_device
|
|
+ * @return N/A
|
|
+ */
|
|
+void
|
|
+uap_proc_entry(uap_private * priv, struct net_device *dev)
|
|
+{
|
|
+ struct proc_dir_entry *r = PROC_DIR;
|
|
+
|
|
+ PRINTM(INFO, "Creating Proc Interface\n");
|
|
+ /* Check if uap directory already exists */
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
|
|
+ for (r = r->subdir; r; r = r->next) {
|
|
+ if (r->namelen && !strcmp("uap", r->name)) {
|
|
+ /* Directory exists */
|
|
+ PRINTM(WARN, "proc directory already exists!\n");
|
|
+ priv->proc_uap = r;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ if (!priv->proc_uap) {
|
|
+ priv->proc_uap = proc_mkdir("uap", PROC_DIR);
|
|
+ if (!priv->proc_uap)
|
|
+ return;
|
|
+ else
|
|
+ atomic_set(&priv->proc_uap->count, 1);
|
|
+ } else {
|
|
+ atomic_inc(&priv->proc_uap->count);
|
|
+ }
|
|
+ priv->proc_entry = proc_mkdir(dev->name, priv->proc_uap);
|
|
+
|
|
+ if (priv->proc_entry) {
|
|
+ r = create_proc_read_entry("info", 0, priv->proc_entry, uap_proc_read,
|
|
+ dev);
|
|
+ r = create_proc_entry("hwstatus", 0644, priv->proc_entry);
|
|
+ if (r) {
|
|
+ r->data = dev;
|
|
+ r->read_proc = uap_hwstatus_read;
|
|
+ r->write_proc = uap_hwstatus_write;
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
|
|
+ r->owner = THIS_MODULE;
|
|
+#endif
|
|
+ } else
|
|
+ PRINTM(MSG, "Fail to create proc hwstatus\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief remove proc file
|
|
+ *
|
|
+ * @param priv pointer uap_private
|
|
+ * @return N/A
|
|
+ */
|
|
+void
|
|
+uap_proc_remove(uap_private * priv)
|
|
+{
|
|
+ if (priv->proc_uap) {
|
|
+ if (priv->proc_entry) {
|
|
+ remove_proc_entry("info", priv->proc_entry);
|
|
+ remove_proc_entry("hwstatus", priv->proc_entry);
|
|
+ }
|
|
+ remove_proc_entry(priv->uap_dev.netdev->name, priv->proc_uap);
|
|
+ atomic_dec(&priv->proc_uap->count);
|
|
+ if (atomic_read(&(priv->proc_uap->count)) == 0)
|
|
+ remove_proc_entry("uap", PROC_DIR);
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief convert string to number
|
|
+ *
|
|
+ * @param s pointer to numbered string
|
|
+ * @return converted number from string s
|
|
+ */
|
|
+int
|
|
+string_to_number(char *s)
|
|
+{
|
|
+ int r = 0;
|
|
+ int base = 0;
|
|
+ int pn = 1;
|
|
+
|
|
+ if (strncmp(s, "-", 1) == 0) {
|
|
+ pn = -1;
|
|
+ s++;
|
|
+ }
|
|
+ if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0)) {
|
|
+ base = 16;
|
|
+ s += 2;
|
|
+ } else
|
|
+ base = 10;
|
|
+
|
|
+ for (s = s; *s != 0; s++) {
|
|
+ if ((*s >= '0') && (*s <= '9'))
|
|
+ r = (r * base) + (*s - '0');
|
|
+ else if ((*s >= 'A') && (*s <= 'F'))
|
|
+ r = (r * base) + (*s - 'A' + 10);
|
|
+ else if ((*s >= 'a') && (*s <= 'f'))
|
|
+ r = (r * base) + (*s - 'a' + 10);
|
|
+ else
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return (r * pn);
|
|
+}
|
|
+
|
|
+#endif
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c
|
|
--- a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c 2012-05-10 00:59:12.998249876 +0000
|
|
@@ -0,0 +1,1428 @@
|
|
+/** @file uap_sdio_mmc.c
|
|
+ * @brief This file contains SDIO IF (interface) module
|
|
+ * related functions.
|
|
+ *
|
|
+ * Copyright (C) 2007-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+/****************************************************
|
|
+Change log:
|
|
+****************************************************/
|
|
+
|
|
+#include "uap_sdio_mmc.h"
|
|
+
|
|
+#include <linux/firmware.h>
|
|
+
|
|
+/** define SDIO block size */
|
|
+/* We support up to 480-byte block size due to FW buffer limitation. */
|
|
+#define SD_BLOCK_SIZE 256
|
|
+
|
|
+/** define allocated buffer size */
|
|
+#define ALLOC_BUF_SIZE (((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
|
|
+ MRVDRV_SIZE_OF_CMD_BUFFER) + INTF_HEADER_LEN \
|
|
+ + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
|
|
+
|
|
+/** Max retry number of CMD53 write */
|
|
+#define MAX_WRITE_IOMEM_RETRY 2
|
|
+
|
|
+/********************************************************
|
|
+ Local Variables
|
|
+********************************************************/
|
|
+
|
|
+/** SDIO Rx unit */
|
|
+static u8 sdio_rx_unit = 0;
|
|
+
|
|
+/**Interrupt status */
|
|
+static u8 sd_ireg = 0;
|
|
+/********************************************************
|
|
+ Global Variables
|
|
+********************************************************/
|
|
+extern u8 *helper_name;
|
|
+extern u8 *fw_name;
|
|
+/** Default helper name */
|
|
+#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
|
|
+/** Default firmware name */
|
|
+#define DEFAULT_FW_NAME "mrvl/sd8688_ap.bin"
|
|
+
|
|
+/********************************************************
|
|
+ Local Functions
|
|
+********************************************************/
|
|
+/**
|
|
+ * @brief This function reads the IO register.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param reg register to be read
|
|
+ * @param dat A pointer to variable that keeps returned value
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sbi_read_ioreg(uap_private * priv, u32 reg, u8 * dat)
|
|
+{
|
|
+ struct sdio_mmc_card *card;
|
|
+ int ret = UAP_STATUS_FAILURE;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ card = priv->uap_dev.card;
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "sbi_read_ioreg(): card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ *dat = sdio_readb(card->func, reg, &ret);
|
|
+ if (ret) {
|
|
+ PRINTM(ERROR, "sbi_read_ioreg(): sdio_readb failed! ret=%d\n", ret);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "sbi_read_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
|
|
+ card->func->num, reg, *dat);
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function writes the IO register.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param reg register to be written
|
|
+ * @param dat the value to be written
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sbi_write_ioreg(uap_private * priv, u32 reg, u8 dat)
|
|
+{
|
|
+ struct sdio_mmc_card *card;
|
|
+ int ret = UAP_STATUS_FAILURE;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ card = priv->uap_dev.card;
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "sbi_write_ioreg(): card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "sbi_write_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
|
|
+ card->func->num, reg, dat);
|
|
+
|
|
+ sdio_writeb(card->func, dat, reg, &ret);
|
|
+ if (ret) {
|
|
+ PRINTM(ERROR, "sbi_write_ioreg(): sdio_readb failed! ret=%d\n", ret);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function get rx_unit value
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sd_get_rx_unit(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u8 reg;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, CARD_RX_UNIT_REG, ®);
|
|
+ if (ret == UAP_STATUS_SUCCESS)
|
|
+ sdio_rx_unit = reg;
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function reads rx length
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param dat A pointer to keep returned data
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sd_read_rx_len(uap_private * priv, u16 * dat)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u8 reg;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, CARD_RX_LEN_REG, ®);
|
|
+ if (ret == UAP_STATUS_SUCCESS)
|
|
+ *dat = (u16) reg << sdio_rx_unit;
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function reads fw status registers
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param dat A pointer to keep returned data
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sd_read_firmware_status(uap_private * priv, u16 * dat)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u8 fws0;
|
|
+ u8 fws1;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, CARD_FW_STATUS0_REG, &fws0);
|
|
+ if (ret < 0) {
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, CARD_FW_STATUS1_REG, &fws1);
|
|
+ if (ret < 0) {
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ *dat = (((u16) fws1) << 8) | fws0;
|
|
+
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function polls the card status register.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param bits the bit mask
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+mv_sdio_poll_card_status(uap_private * priv, u8 bits)
|
|
+{
|
|
+ int tries;
|
|
+ u8 cs;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
|
+ if (sbi_read_ioreg(priv, CARD_STATUS_REG, &cs) < 0)
|
|
+ break;
|
|
+ else if ((cs & bits) == bits) {
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+ }
|
|
+ udelay(10);
|
|
+ }
|
|
+
|
|
+ PRINTM(WARN, "mv_sdio_poll_card_status failed, tries = %d\n", tries);
|
|
+
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function set the sdio bus width.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param mode 1--1 bit mode, 4--4 bit mode
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+#if 0
|
|
+static int
|
|
+sdio_set_bus_width(uap_private * priv, u8 mode)
|
|
+{
|
|
+ ENTER();
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * @brief This function reads data from the card.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+sd_card_to_host(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u16 buf_len = 0;
|
|
+ int buf_block_len;
|
|
+ int blksz;
|
|
+ struct sk_buff *skb = NULL;
|
|
+ u16 type;
|
|
+ u8 *payload = NULL;
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "card or function is NULL!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /* Read the length of data to be transferred */
|
|
+ ret = sd_read_rx_len(priv, &buf_len);
|
|
+ if (ret < 0) {
|
|
+ PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /* Allocate buffer */
|
|
+ blksz = SD_BLOCK_SIZE;
|
|
+ buf_block_len = (buf_len + blksz - 1) / blksz;
|
|
+ if (buf_len <= INTF_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
|
|
+ PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto exit;
|
|
+ }
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ skb = dev_alloc_skb(buf_block_len * blksz + PXA3XX_DMA_ALIGNMENT);
|
|
+#else
|
|
+ skb = dev_alloc_skb(buf_block_len * blksz);
|
|
+#endif
|
|
+ if (skb == NULL) {
|
|
+ PRINTM(WARN, "No free skb\n");
|
|
+ goto exit;
|
|
+ }
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ if ((u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1)) {
|
|
+ skb_put(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
|
|
+ skb_pull(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
|
|
+ }
|
|
+#endif /* PXA3XX_DMA_ALIGN */
|
|
+
|
|
+ payload = skb->tail;
|
|
+ ret = sdio_readsb(card->func, payload, priv->uap_dev.ioport,
|
|
+ buf_block_len * blksz);
|
|
+ if (ret < 0) {
|
|
+ PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto exit;
|
|
+ }
|
|
+ HEXDUMP("SDIO Blk Rd", payload, blksz * buf_block_len);
|
|
+ /*
|
|
+ * This is SDIO specific header
|
|
+ * u16 length,
|
|
+ * u16 type (MV_TYPE_DAT = 0, MV_TYPE_CMD = 1, MV_TYPE_EVENT = 3)
|
|
+ */
|
|
+ buf_len = uap_le16_to_cpu(*(u16 *) & payload[0]);
|
|
+ type = uap_le16_to_cpu(*(u16 *) & payload[2]);
|
|
+ switch (type) {
|
|
+ case MV_TYPE_EVENT:
|
|
+ skb_put(skb, buf_len);
|
|
+ skb_pull(skb, INTF_HEADER_LEN);
|
|
+ uap_process_event(priv, skb->data, skb->len);
|
|
+ kfree_skb(skb);
|
|
+ skb = NULL;
|
|
+ break;
|
|
+ case MV_TYPE_CMD:
|
|
+ skb_put(skb, buf_len);
|
|
+ skb_pull(skb, INTF_HEADER_LEN);
|
|
+ priv->adapter->cmd_pending = FALSE;
|
|
+ if (priv->adapter->cmd_wait_option ==
|
|
+ HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM) {
|
|
+ priv->adapter->cmd_wait_option = FALSE;
|
|
+ uap_process_sleep_confirm_resp(priv, skb->data, skb->len);
|
|
+ } else if (priv->adapter->cmd_wait_option) {
|
|
+ memcpy(priv->adapter->CmdBuf, skb->data, skb->len);
|
|
+ priv->adapter->CmdSize = skb->len;
|
|
+ priv->adapter->cmd_wait_option = FALSE;
|
|
+ priv->adapter->CmdWaitQWoken = TRUE;
|
|
+ wake_up_interruptible(&priv->adapter->cmdwait_q);
|
|
+ }
|
|
+ kfree_skb(skb);
|
|
+ skb = NULL;
|
|
+ break;
|
|
+ case MV_TYPE_DAT:
|
|
+ skb_put(skb, buf_len);
|
|
+ skb_pull(skb, INTF_HEADER_LEN);
|
|
+ uap_process_rx_packet(priv, skb);
|
|
+ break;
|
|
+ default:
|
|
+ priv->stats.rx_errors++;
|
|
+ priv->stats.rx_dropped++;
|
|
+ /* Driver specified event and command resp should be handle here */
|
|
+ PRINTM(INFO, "Unknown PKT type:%d\n", type);
|
|
+ kfree_skb(skb);
|
|
+ skb = NULL;
|
|
+ break;
|
|
+ }
|
|
+ exit:
|
|
+ if (ret) {
|
|
+ if (skb)
|
|
+ kfree_skb(skb);
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function enables the host interrupts mask
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param mask the interrupt mask
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+static int
|
|
+enable_host_int_mask(uap_private * priv, u8 mask)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* Simply write the mask to the register */
|
|
+ ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, mask);
|
|
+
|
|
+ if (ret) {
|
|
+ PRINTM(WARN, "Unable to enable the host interrupt!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/** @brief This function disables the host interrupts mask.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param mask the interrupt mask
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+disable_host_int_mask(uap_private * priv, u8 mask)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u8 host_int_mask;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* Read back the host_int_mask register */
|
|
+ ret = sbi_read_ioreg(priv, HOST_INT_MASK_REG, &host_int_mask);
|
|
+ if (ret) {
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* Update with the mask and write back to the register */
|
|
+ host_int_mask &= ~mask;
|
|
+ ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, host_int_mask);
|
|
+ if (ret < 0) {
|
|
+ PRINTM(WARN, "Unable to diable the host interrupt!\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/********************************************************
|
|
+ Global Functions
|
|
+********************************************************/
|
|
+
|
|
+/**
|
|
+ * @brief This function handles the interrupt.
|
|
+ *
|
|
+ * @param func A pointer to sdio_func structure.
|
|
+ * @return n/a
|
|
+ */
|
|
+static void
|
|
+sbi_interrupt(struct sdio_func *func)
|
|
+{
|
|
+ struct sdio_mmc_card *card;
|
|
+ uap_private *priv;
|
|
+ u8 ireg = 0;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ card = sdio_get_drvdata(func);
|
|
+ if (!card || !card->priv) {
|
|
+ PRINTM(MSG, "%s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
|
|
+ __FUNCTION__, func, card);
|
|
+ LEAVE();
|
|
+ return;
|
|
+ }
|
|
+ priv = card->priv;
|
|
+#ifdef FW_WAKEUP_TIME
|
|
+ if ((priv->adapter->wt_pwrup_sending != 0L) &&
|
|
+ (priv->adapter->wt_int == 0L))
|
|
+ priv->adapter->wt_int = get_utimeofday();
|
|
+#endif
|
|
+
|
|
+ ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
|
|
+ if (ret) {
|
|
+ PRINTM(WARN, "sdio_read_ioreg: read int status register failed\n");
|
|
+ goto done;
|
|
+ }
|
|
+ if (ireg != 0) {
|
|
+ /*
|
|
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
|
|
+ * Clear the interrupt status register and re-enable the interrupt
|
|
+ */
|
|
+ PRINTM(INFO, "sdio_ireg = 0x%x\n", ireg);
|
|
+ sdio_writeb(card->func,
|
|
+ ~(ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS),
|
|
+ HOST_INTSTATUS_REG, &ret);
|
|
+ if (ret) {
|
|
+ PRINTM(WARN,
|
|
+ "sdio_write_ioreg: clear int status register failed\n");
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+ OS_INT_DISABLE;
|
|
+ sd_ireg |= ireg;
|
|
+ OS_INT_RESTORE;
|
|
+
|
|
+ uap_interrupt(priv);
|
|
+ done:
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function probe the card
|
|
+ *
|
|
+ * @param func A pointer to sdio_func structure
|
|
+ * @param id A pointer to structure sd_device_id
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+static int
|
|
+uap_probe(struct sdio_func *func, const struct sdio_device_id *id)
|
|
+{
|
|
+ int ret = UAP_STATUS_FAILURE;
|
|
+ struct sdio_mmc_card *card = NULL;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ PRINTM(MSG, "%s: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
|
|
+ __FUNCTION__, func->vendor, func->device, func->class, func->num);
|
|
+
|
|
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
|
|
+ if (!card) {
|
|
+ ret = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ card->func = func;
|
|
+
|
|
+ if (!uap_add_card(card)) {
|
|
+ PRINTM(ERROR, "%s: uap_add_callback failed\n", __FUNCTION__);
|
|
+ kfree(card);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function removes the card
|
|
+ *
|
|
+ * @param func A pointer to sdio_func structure
|
|
+ * @return N/A
|
|
+ */
|
|
+static void
|
|
+uap_remove(struct sdio_func *func)
|
|
+{
|
|
+ struct sdio_mmc_card *card;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (func) {
|
|
+ card = sdio_get_drvdata(func);
|
|
+ if (card) {
|
|
+ uap_remove_card(card);
|
|
+ kfree(card);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM
|
|
+/**
|
|
+ * @brief This function handles client driver suspend
|
|
+ *
|
|
+ * @param func A pointer to sdio_func structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+uap_suspend(struct sdio_func *func)
|
|
+{
|
|
+ ENTER();
|
|
+ LEAVE();
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function handles client driver resume
|
|
+ *
|
|
+ * @param func A pointer to sdio_func structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+uap_resume(struct sdio_func *func)
|
|
+{
|
|
+ ENTER();
|
|
+ LEAVE();
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/** Device ID for SD8688 */
|
|
+#define SD_DEVICE_ID_8688_UAP 0x9104
|
|
+/** UAP IDs */
|
|
+static const struct sdio_device_id uap_ids[] = {
|
|
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SD_DEVICE_ID_8688_UAP)},
|
|
+ {},
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(sdio, uap_ids);
|
|
+
|
|
+static struct sdio_driver uap_sdio = {
|
|
+ .name = "uap_sdio",
|
|
+ .id_table = uap_ids,
|
|
+ .probe = uap_probe,
|
|
+ .remove = uap_remove,
|
|
+#ifdef CONFIG_PM
|
|
+/* .suspend = uap_suspend, */
|
|
+/* .resume = uap_resume, */
|
|
+#endif
|
|
+
|
|
+};
|
|
+
|
|
+/**
|
|
+ * @brief This function registers the IF module in bus driver.
|
|
+ *
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int __init
|
|
+sbi_register()
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ /* SDIO Driver Registration */
|
|
+ if (sdio_register_driver(&uap_sdio) != 0) {
|
|
+ PRINTM(FATAL, "SDIO Driver Registration Failed \n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function de-registers the IF module in bus driver.
|
|
+ *
|
|
+ * @return n/a
|
|
+ */
|
|
+void __exit
|
|
+sbi_unregister(void)
|
|
+{
|
|
+ ENTER();
|
|
+
|
|
+ /* SDIO Driver Unregistration */
|
|
+ sdio_unregister_driver(&uap_sdio);
|
|
+
|
|
+ LEAVE();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function checks the interrupt status and handle it accordingly.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param ireg A pointer to variable that keeps returned value
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_get_int_status(uap_private * priv, u8 * ireg)
|
|
+{
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u8 sdio_ireg = 0;
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ *ireg = 0;
|
|
+ OS_INT_DISABLE;
|
|
+ sdio_ireg = sd_ireg;
|
|
+ sd_ireg = 0;
|
|
+ OS_INT_RESTORE;
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+
|
|
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT */
|
|
+ if (!priv->uap_dev.cmd_sent) { /* tx_done already received */
|
|
+ PRINTM(INFO,
|
|
+ "warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
|
|
+ priv->uap_dev.cmd_sent, sdio_ireg);
|
|
+ } else {
|
|
+ priv->uap_dev.cmd_sent = FALSE;
|
|
+ priv->uap_dev.data_sent = FALSE;
|
|
+ if ( (priv->uap_dev.netdev->reg_state == NETREG_REGISTERED) && (skb_queue_len(&priv->adapter->tx_queue) < TX_LOW_WATERMARK)) {
|
|
+ os_start_queue(priv);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
|
|
+ sd_card_to_host(priv);
|
|
+ }
|
|
+
|
|
+ *ireg = sdio_ireg;
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ sdio_release_host(card->func);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function disables the host interrupts.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_disable_host_int(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ int ret;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+ ret = disable_host_int_mask(priv, HIM_DISABLE);
|
|
+ sdio_release_host(card->func);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function enables the host interrupts.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+int
|
|
+sbi_enable_host_int(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ int ret;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+ ret = enable_host_int_mask(priv, HIM_ENABLE);
|
|
+ sdio_release_host(card->func);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function de-registers the device.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+int
|
|
+sbi_unregister_dev(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "Error: card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+ sdio_release_irq(card->func);
|
|
+ sdio_disable_func(card->func);
|
|
+ sdio_release_host(card->func);
|
|
+
|
|
+ sdio_set_drvdata(card->func, NULL);
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function registers the device.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_register_dev(uap_private * priv)
|
|
+{
|
|
+ int ret = UAP_STATUS_FAILURE;
|
|
+ u8 reg;
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ struct sdio_func *func;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "Error: card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ func = card->func;
|
|
+
|
|
+ /* Initialize the private structure */
|
|
+ priv->uap_dev.ioport = 0;
|
|
+
|
|
+ sdio_claim_host(func);
|
|
+
|
|
+ ret = sdio_enable_func(func);
|
|
+ if (ret) {
|
|
+ PRINTM(FATAL, "sdio_enable_func() failed: ret=%d\n", ret);
|
|
+ goto release_host;
|
|
+ }
|
|
+
|
|
+ ret = sdio_claim_irq(func, sbi_interrupt);
|
|
+ if (ret) {
|
|
+ PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
|
|
+ goto disable_func;
|
|
+ }
|
|
+
|
|
+ /* Read the IO port */
|
|
+ ret = sbi_read_ioreg(priv, IO_PORT_0_REG, ®);
|
|
+ if (ret)
|
|
+ goto release_irq;
|
|
+ else
|
|
+ priv->uap_dev.ioport |= reg;
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, IO_PORT_1_REG, ®);
|
|
+ if (ret)
|
|
+ goto release_irq;
|
|
+ else
|
|
+ priv->uap_dev.ioport |= (reg << 8);
|
|
+
|
|
+ ret = sbi_read_ioreg(priv, IO_PORT_2_REG, ®);
|
|
+ if (ret)
|
|
+ goto release_irq;
|
|
+ else
|
|
+ priv->uap_dev.ioport |= (reg << 16);
|
|
+
|
|
+ PRINTM(INFO, "SDIO FUNC #%d IO port: 0x%x\n", func->num,
|
|
+ priv->uap_dev.ioport);
|
|
+
|
|
+ ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
|
|
+ if (ret) {
|
|
+ PRINTM(ERROR, "%s: cannot set SDIO block size\n", __FUNCTION__);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto release_irq;
|
|
+ }
|
|
+ priv->hotplug_device = &func->dev;
|
|
+
|
|
+ if (helper_name == NULL) {
|
|
+ helper_name = DEFAULT_HELPER_NAME;
|
|
+ }
|
|
+ if (fw_name == NULL) {
|
|
+ fw_name = DEFAULT_FW_NAME;
|
|
+ }
|
|
+ sdio_release_host(func);
|
|
+
|
|
+ sdio_set_drvdata(func, card);
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ goto done;
|
|
+
|
|
+ release_irq:
|
|
+ sdio_release_irq(func);
|
|
+ disable_func:
|
|
+ sdio_disable_func(func);
|
|
+ release_host:
|
|
+ sdio_release_host(func);
|
|
+
|
|
+ done:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function sends data to the card.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param payload A pointer to the data/cmd buffer
|
|
+ * @param nb the length of data/cmd
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ int buf_block_len;
|
|
+ int blksz;
|
|
+ int i = 0;
|
|
+ u8 *buf = NULL;
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ void *tmpbuf = NULL;
|
|
+ int tmpbufsz;
|
|
+#endif
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "card or function is NULL!\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+ buf = payload;
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ if ((u32) payload & (PXA3XX_DMA_ALIGNMENT - 1)) {
|
|
+ tmpbufsz = ALIGN_SZ(nb, PXA3XX_DMA_ALIGNMENT);
|
|
+ tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
|
|
+ memset(tmpbuf, 0, tmpbufsz);
|
|
+ /* Ensure 8-byte aligned CMD buffer */
|
|
+ buf = (u8 *) ALIGN_ADDR(tmpbuf, PXA3XX_DMA_ALIGNMENT);
|
|
+ memcpy(buf, payload, nb);
|
|
+ }
|
|
+#endif
|
|
+ /* Allocate buffer and copy payload */
|
|
+ blksz = SD_BLOCK_SIZE;
|
|
+ buf_block_len = (nb + blksz - 1) / blksz;
|
|
+ sdio_claim_host(card->func);
|
|
+#define MAX_WRITE_IOMEM_RETRY 2
|
|
+ priv->uap_dev.cmd_sent = TRUE;
|
|
+ priv->uap_dev.data_sent = TRUE;
|
|
+ do {
|
|
+ /* Transfer data to card */
|
|
+ ret = sdio_writesb(card->func, priv->uap_dev.ioport, buf,
|
|
+ buf_block_len * blksz);
|
|
+ if (ret < 0) {
|
|
+ i++;
|
|
+ PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
|
|
+ ret);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ if (i > MAX_WRITE_IOMEM_RETRY)
|
|
+ goto exit;
|
|
+ } else {
|
|
+ HEXDUMP("SDIO Blk Wr", payload, nb);
|
|
+ }
|
|
+ } while (ret == UAP_STATUS_FAILURE);
|
|
+ exit:
|
|
+ sdio_release_host(card->func);
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ if (tmpbuf)
|
|
+ kfree(tmpbuf);
|
|
+#endif
|
|
+ if (ret == UAP_STATUS_FAILURE) {
|
|
+ priv->uap_dev.cmd_sent = FALSE;
|
|
+ priv->uap_dev.data_sent = FALSE;
|
|
+ }
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function reads CIS information.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param cisinfo A pointer to CIS information output buffer
|
|
+ * @param cislen A pointer to length of CIS info output buffer
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+#if 0
|
|
+static int
|
|
+sbi_get_cis_info(uap_private * priv, void *cisinfo, int *cislen)
|
|
+{
|
|
+#define CIS_PTR (0x8000)
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ unsigned int i, cis_ptr = CIS_PTR;
|
|
+ int ret = UAP_STATUS_FAILURE;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "sbi_get_cis_info(): card or function is NULL!\n");
|
|
+ goto exit;
|
|
+ }
|
|
+#define MAX_SDIO_CIS_INFO_LEN (256)
|
|
+ if (!cisinfo || (*cislen < MAX_SDIO_CIS_INFO_LEN)) {
|
|
+ PRINTM(WARN, "ERROR! get_cis_info: insufficient buffer passed\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ *cislen = MAX_SDIO_CIS_INFO_LEN;
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+
|
|
+ PRINTM(INFO, "cis_ptr=%#x\n", cis_ptr);
|
|
+
|
|
+ /* Read the Tuple Data */
|
|
+ for (i = 0; i < *cislen; i++) {
|
|
+ ((unsigned char *) cisinfo)[i] =
|
|
+ sdio_readb(card->func, cis_ptr + i, &ret);
|
|
+ if (ret) {
|
|
+ PRINTM(WARN, "get_cis_info error: ret=%d\n", ret);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ PRINTM(INFO, "cisinfo[%d]=%#x\n", i, ((unsigned char *) cisinfo)[i]);
|
|
+ }
|
|
+
|
|
+ done:
|
|
+ sdio_release_host(card->func);
|
|
+ exit:
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
+/**
|
|
+ * @brief This function downloads helper image to the card.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_prog_helper(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ u8 *helper = NULL;
|
|
+ int helperlen;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ void *tmphlprbuf = NULL;
|
|
+ int tmphlprbufsz;
|
|
+ u8 *hlprbuf;
|
|
+ int hlprblknow;
|
|
+ u32 tx_len;
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ u32 tv1, tv2;
|
|
+#endif
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "sbi_prog_helper(): card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ if (priv->fw_helper) {
|
|
+ helper = (u8 *) priv->fw_helper->data;
|
|
+ helperlen = priv->fw_helper->size;
|
|
+ } else {
|
|
+ PRINTM(MSG, "No helper image found! Terminating download.\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
|
|
+ helperlen, SD_BLOCK_SIZE);
|
|
+
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ tv1 = get_utimeofday();
|
|
+#endif
|
|
+
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ tmphlprbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
|
|
+#else /* !PXA3XX_DMA_ALIGN */
|
|
+ tmphlprbufsz = UAP_UPLD_SIZE;
|
|
+#endif /* !PXA3XX_DMA_ALIGN */
|
|
+ tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
|
|
+ if (!tmphlprbuf) {
|
|
+ PRINTM(ERROR,
|
|
+ "Unable to allocate buffer for helper. Terminating download\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ memset(tmphlprbuf, 0, tmphlprbufsz);
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ hlprbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, PXA3XX_DMA_ALIGNMENT);
|
|
+#else /* !PXA3XX_DMA_ALIGN */
|
|
+ hlprbuf = (u8 *) tmphlprbuf;
|
|
+#endif /* !PXA3XX_DMA_ALIGN */
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+
|
|
+ /* Perform helper data transfer */
|
|
+ tx_len = (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE) - INTF_HEADER_LEN;
|
|
+ hlprblknow = 0;
|
|
+ do {
|
|
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
|
|
+ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
|
|
+ if (ret < 0) {
|
|
+ PRINTM(FATAL, "Helper download poll status timeout @ %d\n",
|
|
+ hlprblknow);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* More data? */
|
|
+ if (hlprblknow >= helperlen)
|
|
+ break;
|
|
+
|
|
+ /* Set blocksize to transfer - checking for last block */
|
|
+ if (helperlen - hlprblknow < tx_len)
|
|
+ tx_len = helperlen - hlprblknow;
|
|
+
|
|
+ /* Set length to the 4-byte header */
|
|
+ *(u32 *) hlprbuf = uap_cpu_to_le32(tx_len);
|
|
+
|
|
+ /* Copy payload to buffer */
|
|
+ memcpy(&hlprbuf[INTF_HEADER_LEN], &helper[hlprblknow], tx_len);
|
|
+
|
|
+ PRINTM(INFO, ".");
|
|
+
|
|
+ /* Send data */
|
|
+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
|
|
+ hlprbuf, FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ PRINTM(FATAL, "IO error during helper download @ %d\n", hlprblknow);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ hlprblknow += tx_len;
|
|
+ } while (TRUE);
|
|
+
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ tv2 = get_utimeofday();
|
|
+ PRINTM(INFO, "helper: %ld.%03ld.%03ld ", tv1 / 1000000,
|
|
+ (tv1 % 1000000) / 1000, tv1 % 1000);
|
|
+ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000,
|
|
+ tv2 % 1000);
|
|
+ tv2 -= tv1;
|
|
+ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000,
|
|
+ tv2 % 1000);
|
|
+#endif
|
|
+
|
|
+ /* Write last EOF data */
|
|
+ PRINTM(INFO, "\nTransferring helper image EOF block\n");
|
|
+ memset(hlprbuf, 0x0, SD_BLOCK_SIZE);
|
|
+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
|
|
+ hlprbuf, SD_BLOCK_SIZE);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ PRINTM(FATAL, "IO error in writing helper image EOF block\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ done:
|
|
+ sdio_release_host(card->func);
|
|
+ if (tmphlprbuf)
|
|
+ kfree(tmphlprbuf);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function downloads firmware image to the card.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_prog_fw_w_helper(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ u8 *firmware = NULL;
|
|
+ int firmwarelen;
|
|
+ u8 base0;
|
|
+ u8 base1;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ int offset;
|
|
+ void *tmpfwbuf = NULL;
|
|
+ int tmpfwbufsz;
|
|
+ u8 *fwbuf;
|
|
+ u16 len;
|
|
+ int txlen = 0;
|
|
+ int tx_blocks = 0;
|
|
+ int i = 0;
|
|
+ int tries = 0;
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ u32 tv1, tv2;
|
|
+#endif
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "sbi_prog_fw_w_helper(): card or function is NULL!\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ if (priv->firmware) {
|
|
+ firmware = (u8 *) priv->firmware->data;
|
|
+ firmwarelen = priv->firmware->size;
|
|
+ } else {
|
|
+ PRINTM(MSG, "No firmware image found! Terminating download.\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+
|
|
+ PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
|
|
+
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ tv1 = get_utimeofday();
|
|
+#endif
|
|
+
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ tmpfwbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
|
|
+#else /* PXA3XX_DMA_ALIGN */
|
|
+ tmpfwbufsz = UAP_UPLD_SIZE;
|
|
+#endif /* PXA3XX_DMA_ALIGN */
|
|
+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
|
|
+ if (!tmpfwbuf) {
|
|
+ PRINTM(ERROR,
|
|
+ "Unable to allocate buffer for firmware. Terminating download.\n");
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ memset(tmpfwbuf, 0, tmpfwbufsz);
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+ /* Ensure 8-byte aligned firmware buffer */
|
|
+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT);
|
|
+#else /* PXA3XX_DMA_ALIGN */
|
|
+ fwbuf = (u8 *) tmpfwbuf;
|
|
+#endif /* PXA3XX_DMA_ALIGN */
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+
|
|
+ /* Perform firmware data transfer */
|
|
+ offset = 0;
|
|
+ do {
|
|
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
|
|
+ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
|
|
+ if (ret < 0) {
|
|
+ PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n",
|
|
+ offset);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* More data? */
|
|
+ if (offset >= firmwarelen)
|
|
+ break;
|
|
+
|
|
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
|
+ if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_0, &base0)) < 0) {
|
|
+ PRINTM(WARN, "Dev BASE0 register read failed:"
|
|
+ " base0=0x%04X(%d). Terminating download.\n", base0,
|
|
+ base0);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_1, &base1)) < 0) {
|
|
+ PRINTM(WARN, "Dev BASE1 register read failed:"
|
|
+ " base1=0x%04X(%d). Terminating download.\n", base1,
|
|
+ base1);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ len = (((u16) base1) << 8) | base0;
|
|
+
|
|
+ /* For SD8688 wait until the length is not 0, 1 or 2 before
|
|
+ downloading the first FW block, since BOOT code writes the
|
|
+ register to indicate the helper/FW download winner, the value
|
|
+ could be 1 or 2 (Func1 or Func2). */
|
|
+ if ((len && offset) || (len > 2))
|
|
+ break;
|
|
+ udelay(10);
|
|
+ }
|
|
+
|
|
+ if (len == 0)
|
|
+ break;
|
|
+ else if (len > UAP_UPLD_SIZE) {
|
|
+ PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
|
|
+ offset, len);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ txlen = len;
|
|
+
|
|
+ if (len & BIT(0)) {
|
|
+ i++;
|
|
+ if (i > MAX_WRITE_IOMEM_RETRY) {
|
|
+ PRINTM(FATAL,
|
|
+ "FW download failure @ %d, over max retry count\n",
|
|
+ offset);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ goto done;
|
|
+ }
|
|
+ PRINTM(ERROR, "FW CRC error indicated by the helper:"
|
|
+ " len = 0x%04X, txlen = %d\n", len, txlen);
|
|
+ len &= ~BIT(0);
|
|
+ /* Setting this to 0 to resend from same offset */
|
|
+ txlen = 0;
|
|
+ } else {
|
|
+ i = 0;
|
|
+
|
|
+ /* Set blocksize to transfer - checking for last block */
|
|
+ if (firmwarelen - offset < txlen) {
|
|
+ txlen = firmwarelen - offset;
|
|
+ }
|
|
+ PRINTM(INFO, ".");
|
|
+
|
|
+ tx_blocks = (txlen + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE;
|
|
+
|
|
+ /* Copy payload to buffer */
|
|
+ memcpy(fwbuf, &firmware[offset], txlen);
|
|
+ }
|
|
+
|
|
+ /* Send data */
|
|
+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
|
|
+ fwbuf, tx_blocks * SD_BLOCK_SIZE);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
|
|
+ offset);
|
|
+ if (sbi_write_ioreg(priv, CONFIGURATION_REG, 0x04) < 0) {
|
|
+ PRINTM(ERROR, "write ioreg failed (CFG)\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ offset += txlen;
|
|
+ } while (TRUE);
|
|
+
|
|
+ PRINTM(INFO, "\nFW download over, size %d bytes\n", offset);
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ done:
|
|
+#ifdef FW_DOWNLOAD_SPEED
|
|
+ tv2 = get_utimeofday();
|
|
+ PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
|
|
+ (tv1 % 1000000) / 1000, tv1 % 1000);
|
|
+ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
|
|
+ (tv2 % 1000000) / 1000, tv2 % 1000);
|
|
+ tv2 -= tv1;
|
|
+ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
|
|
+ (tv2 % 1000000) / 1000, tv2 % 1000);
|
|
+#endif
|
|
+ sdio_release_host(card->func);
|
|
+ if (tmpfwbuf)
|
|
+ kfree(tmpfwbuf);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function checks if the firmware is ready to accept
|
|
+ * command or not.
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param pollnum Poll number
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_check_fw_status(uap_private * priv, int pollnum)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+ u16 firmwarestat;
|
|
+ int tries;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ sdio_claim_host(card->func);
|
|
+
|
|
+ /* Wait for firmware initialization event */
|
|
+ for (tries = 0; tries < pollnum; tries++) {
|
|
+ if ((ret = sd_read_firmware_status(priv, &firmwarestat)) < 0)
|
|
+ continue;
|
|
+ if (firmwarestat == FIRMWARE_READY) {
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ break;
|
|
+ } else {
|
|
+ mdelay(10);
|
|
+ ret = UAP_STATUS_FAILURE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ret < 0)
|
|
+ goto done;
|
|
+
|
|
+ ret = UAP_STATUS_SUCCESS;
|
|
+ sd_get_rx_unit(priv);
|
|
+
|
|
+ done:
|
|
+ sdio_release_host(card->func);
|
|
+
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function set bus clock on/off
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @param option TRUE--on , FALSE--off
|
|
+ * @return UAP_STATUS_SUCCESS
|
|
+ */
|
|
+#if 0
|
|
+static int
|
|
+sbi_set_bus_clock(uap_private * priv, u8 option)
|
|
+{
|
|
+ ENTER();
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_SUCCESS;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * @brief This function wakeup firmware
|
|
+ *
|
|
+ * @param priv A pointer to uap_private structure
|
|
+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
|
|
+ */
|
|
+int
|
|
+sbi_wakeup_firmware(uap_private * priv)
|
|
+{
|
|
+ struct sdio_mmc_card *card = priv->uap_dev.card;
|
|
+ int ret = UAP_STATUS_SUCCESS;
|
|
+
|
|
+ ENTER();
|
|
+
|
|
+ if (!card || !card->func) {
|
|
+ PRINTM(ERROR, "card or function is NULL!\n");
|
|
+ LEAVE();
|
|
+ return UAP_STATUS_FAILURE;
|
|
+ }
|
|
+ sdio_claim_host(card->func);
|
|
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
|
|
+ sdio_release_host(card->func);
|
|
+ LEAVE();
|
|
+ return ret;
|
|
+}
|
|
diff -urN a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h
|
|
--- a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h 1970-01-01 00:00:00.000000000 +0000
|
|
+++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h 2012-05-10 00:59:13.006062669 +0000
|
|
@@ -0,0 +1,136 @@
|
|
+/** @file uap_sdio_mmc.h
|
|
+ * @brief This file contains SDIO IF (interface) module
|
|
+ * related macros, enum, and structure.
|
|
+ *
|
|
+ * Copyright (C) 2007-2009, Marvell International Ltd.
|
|
+ *
|
|
+ * This software file (the "File") is distributed by Marvell International
|
|
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
+ * (the "License"). You may use, redistribute and/or modify this File in
|
|
+ * accordance with the terms and conditions of the License, a copy of which
|
|
+ * is available along with the File in the gpl.txt file or by writing to
|
|
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
+ *
|
|
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
+ * this warranty disclaimer.
|
|
+ *
|
|
+ */
|
|
+/****************************************************
|
|
+Change log:
|
|
+ 10/10/07: initial version
|
|
+****************************************************/
|
|
+
|
|
+#ifndef _UAP_SDIO_MMC_H
|
|
+#define _UAP_SDIO_MMC_H
|
|
+
|
|
+#include <linux/mmc/sdio.h>
|
|
+#include <linux/mmc/sdio_ids.h>
|
|
+#include <linux/mmc/sdio_func.h>
|
|
+#include <linux/mmc/card.h>
|
|
+
|
|
+#include "uap_headers.h"
|
|
+
|
|
+/** The number of times to try when waiting for downloaded firmware to
|
|
+ become active. (polling the scratch register). */
|
|
+#define MAX_FIRMWARE_POLL_TRIES 100
|
|
+
|
|
+/** Firmware ready */
|
|
+#define FIRMWARE_READY 0xfedc
|
|
+
|
|
+/** Number of firmware blocks to transfer */
|
|
+#define FIRMWARE_TRANSFER_NBLOCK 2
|
|
+
|
|
+/* Host Control Registers */
|
|
+/** Host Control Registers : I/O port 0 */
|
|
+#define IO_PORT_0_REG 0x00
|
|
+/** Host Control Registers : I/O port 1 */
|
|
+#define IO_PORT_1_REG 0x01
|
|
+/** Host Control Registers : I/O port 2 */
|
|
+#define IO_PORT_2_REG 0x02
|
|
+
|
|
+/** Host Control Registers : Configuration */
|
|
+#define CONFIGURATION_REG 0x03
|
|
+/** Host Control Registers : Host without Command 53 finish host */
|
|
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
|
|
+/** Host Control Registers : Host power up */
|
|
+#define HOST_POWER_UP (0x1U << 1)
|
|
+/** Host Control Registers : Host power down */
|
|
+#define HOST_POWER_DOWN (0x1U << 0)
|
|
+
|
|
+/** Host Control Registers : Host interrupt mask */
|
|
+#define HOST_INT_MASK_REG 0x04
|
|
+/** Host Control Registers : Upload host interrupt mask */
|
|
+#define UP_LD_HOST_INT_MASK (0x1U)
|
|
+/** Host Control Registers : Download host interrupt mask */
|
|
+#define DN_LD_HOST_INT_MASK (0x2U)
|
|
+/** Enable Host interrupt mask */
|
|
+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
|
|
+/** Disable Host interrupt mask */
|
|
+#define HIM_DISABLE 0xff
|
|
+
|
|
+/** Host Control Registers : Host interrupt status */
|
|
+#define HOST_INTSTATUS_REG 0x05
|
|
+/** Host Control Registers : Upload host interrupt status */
|
|
+#define UP_LD_HOST_INT_STATUS (0x1U)
|
|
+/** Host Control Registers : Download host interrupt status */
|
|
+#define DN_LD_HOST_INT_STATUS (0x2U)
|
|
+
|
|
+/** Host F1 read base 0 */
|
|
+#define HOST_F1_RD_BASE_0 0x10
|
|
+/** Host F1 read base 1 */
|
|
+#define HOST_F1_RD_BASE_1 0x11
|
|
+
|
|
+/** Card Control Registers : Card status register */
|
|
+#define CARD_STATUS_REG 0x20
|
|
+/** Card Control Registers : Card I/O ready */
|
|
+#define CARD_IO_READY (0x1U << 3)
|
|
+/** Card Control Registers : CIS card ready */
|
|
+#define CIS_CARD_RDY (0x1U << 2)
|
|
+/** Card Control Registers : Upload card ready */
|
|
+#define UP_LD_CARD_RDY (0x1U << 1)
|
|
+/** Card Control Registers : Download card ready */
|
|
+#define DN_LD_CARD_RDY (0x1U << 0)
|
|
+
|
|
+/** Card Control Registers : Card OCR 0 register */
|
|
+#define CARD_OCR_0_REG 0x34
|
|
+/** Card Control Registers : Card OCR 1 register */
|
|
+#define CARD_OCR_1_REG 0x35
|
|
+
|
|
+/** Firmware status 0 register */
|
|
+#define CARD_FW_STATUS0_REG 0x40
|
|
+/** Firmware status 1 register */
|
|
+#define CARD_FW_STATUS1_REG 0x41
|
|
+/** Rx length register */
|
|
+#define CARD_RX_LEN_REG 0x42
|
|
+/** Rx unit register */
|
|
+#define CARD_RX_UNIT_REG 0x43
|
|
+
|
|
+/** Chip Id Register 0 */
|
|
+#define CARD_CHIP_ID_0_REG 0x801c
|
|
+/** Chip Id Register 1 */
|
|
+#define CARD_CHIP_ID_1_REG 0x801d
|
|
+
|
|
+#ifdef PXA3XX_DMA_ALIGN
|
|
+/** DMA alignment value for PXA3XX platforms */
|
|
+#define PXA3XX_DMA_ALIGNMENT 8
|
|
+/** Macros for Data Alignment : size */
|
|
+#define ALIGN_SZ(p, a) \
|
|
+ (((p) + ((a) - 1)) & ~((a) - 1))
|
|
+
|
|
+/** Macros for Data Alignment : address */
|
|
+#define ALIGN_ADDR(p, a) \
|
|
+ ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1))
|
|
+#endif /* PXA3XX_DMA_ALIGN */
|
|
+
|
|
+struct sdio_mmc_card
|
|
+{
|
|
+ /** sdio_func structure pointer */
|
|
+ struct sdio_func *func;
|
|
+ /** uap_private structure pointer */
|
|
+ uap_private *priv;
|
|
+};
|
|
+
|
|
+#endif /* _UAP_SDIO_MMC_H */
|
|
diff -urN a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
|
|
--- a/drivers/net/wireless/Makefile 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/net/wireless/Makefile 2012-05-10 00:59:13.021688255 +0000
|
|
@@ -37,6 +37,8 @@
|
|
|
|
obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/
|
|
|
|
+obj-$(CONFIG_LIBERTAS_UAP) += libertas_uap/
|
|
+
|
|
obj-$(CONFIG_ADM8211) += adm8211.o
|
|
|
|
obj-$(CONFIG_MWL8K) += mwl8k.o
|
|
diff -urN a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
|
|
--- a/drivers/net/wireless/mwifiex/sdio.c 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/net/wireless/mwifiex/sdio.c 2012-05-10 00:59:13.045126631 +0000
|
|
@@ -253,11 +253,14 @@
|
|
return 0;
|
|
}
|
|
|
|
+/* Device ID for SD8786 */
|
|
+#define SDIO_DEVICE_ID_MARVELL_8786 (0x9116)
|
|
/* Device ID for SD8787 */
|
|
#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
|
|
|
|
/* WLAN IDs */
|
|
static const struct sdio_device_id mwifiex_ids[] = {
|
|
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786)},
|
|
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
|
|
{},
|
|
};
|
|
@@ -1570,7 +1573,15 @@
|
|
sdio_set_drvdata(func, card);
|
|
|
|
adapter->dev = &func->dev;
|
|
- strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME);
|
|
+ switch (func->device) {
|
|
+ case SDIO_DEVICE_ID_MARVELL_8786:
|
|
+ strcpy(adapter->fw_name, SD8786_DEFAULT_FW_NAME);
|
|
+ break;
|
|
+ case SDIO_DEVICE_ID_MARVELL_8787:
|
|
+ default:
|
|
+ strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME);
|
|
+ break;
|
|
+ }
|
|
|
|
return 0;
|
|
|
|
@@ -1769,4 +1780,5 @@
|
|
MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
|
|
MODULE_VERSION(SDIO_VERSION);
|
|
MODULE_LICENSE("GPL v2");
|
|
-MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
|
+MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME);
|
|
+MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);
|
|
diff -urN a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
|
|
--- a/drivers/net/wireless/mwifiex/sdio.h 2011-10-24 07:10:05.000000000 +0000
|
|
+++ b/drivers/net/wireless/mwifiex/sdio.h 2012-05-10 00:59:13.052939423 +0000
|
|
@@ -28,6 +28,7 @@
|
|
|
|
#include "main.h"
|
|
|
|
+#define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin"
|
|
#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
|
|
|
|
#define BLOCK_MODE 1
|
|
diff -rupN a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
|
|
--- a/arch/arm/mach-kirkwood/Kconfig 2012-08-19 22:10:00.030821001 -0400
|
|
+++ b/arch/arm/mach-kirkwood/Kconfig 2012-08-19 22:27:54.040824257 -0400
|
|
@@ -178,6 +178,18 @@ config MACH_T5325
|
|
Say 'Y' here if you want your kernel to support the
|
|
HP t5325 Thin Client.
|
|
|
|
+config MACH_NSA310
|
|
+ bool "ZyXEL NSA310 1-Bay Power Media Server"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ ZyXEL NSA310.
|
|
+
|
|
+config MACH_NSA320
|
|
+ bool "ZyXEL NSA320 2-Bay Power Media Server"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ ZyXEL NSA320.
|
|
+
|
|
endmenu
|
|
|
|
endif
|
|
diff -rupN a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
|
|
--- a/arch/arm/mach-kirkwood/Makefile 2012-08-19 22:10:00.030821001 -0400
|
|
+++ b/arch/arm/mach-kirkwood/Makefile 2012-08-19 22:28:17.850820490 -0400
|
|
@@ -26,5 +26,7 @@ obj-$(CONFIG_MACH_D2NET_V2) += d2net_v2
|
|
obj-$(CONFIG_MACH_NET2BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o
|
|
obj-$(CONFIG_MACH_NET5BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o
|
|
obj-$(CONFIG_MACH_T5325) += t5325-setup.o
|
|
+obj-$(CONFIG_MACH_NSA310) += nsa310-setup.o
|
|
+obj-$(CONFIG_MACH_NSA320) += nsa320-setup.o
|
|
|
|
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
|
diff -rupN a/arch/arm/mach-kirkwood/nsa310-setup.c b/arch/arm/mach-kirkwood/nsa310-setup.c
|
|
--- a/arch/arm/mach-kirkwood/nsa310-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/nsa310-setup.c 2012-08-20 00:08:42.280823844 -0400
|
|
@@ -0,0 +1,357 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/nsa310-setup.c
|
|
+ *
|
|
+ * Zyxel NSA-310 Setup, by AA666 and Peeter123
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <mtd/mtd-abi.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/mv643xx_i2c.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include <plat/mvsdio.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+#include <linux/timer.h>
|
|
+#include <linux/jiffies.h>
|
|
+
|
|
+static void nsa310_timerfunc(unsigned long data);
|
|
+static DEFINE_TIMER(timer, nsa310_timerfunc, 0, 0);
|
|
+
|
|
+static struct mtd_partition nsa310_nand_parts[] = {
|
|
+ {
|
|
+ .name = "uboot",
|
|
+ .offset = 0,
|
|
+ .size = 0x100000,
|
|
+ .mask_flags = MTD_WRITEABLE
|
|
+ }, {
|
|
+ .name = "uboot_env",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0x80000
|
|
+ }, {
|
|
+ .name = "key_store",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0x80000
|
|
+ }, {
|
|
+ .name = "info",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0x80000
|
|
+ }, {
|
|
+ .name = "etc",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0xA00000
|
|
+ }, {
|
|
+ .name = "kernel_1",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0xA00000
|
|
+ }, {
|
|
+ .name = "rootfs1",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0x2FC0000
|
|
+ }, {
|
|
+ .name = "kernel_2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0xA00000
|
|
+ }, {
|
|
+ .name = "rootfs2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 0x2FC0000
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct i2c_board_info __initdata nsa310_i2c_rtc = {
|
|
+ I2C_BOARD_INFO("pcf8563", 0x51),
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data nsa310_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+ .speed = SPEED_1000,
|
|
+ .duplex = DUPLEX_FULL,
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data nsa310_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static unsigned int nsa310_mpp_config[] __initdata = {
|
|
+ MPP36_GPIO, // Reset button
|
|
+ MPP37_GPIO, // Copy button
|
|
+ MPP46_GPIO, // Power button
|
|
+
|
|
+ MPP48_GPIO, // Power Off
|
|
+ MPP21_GPIO, // USB Power Off
|
|
+
|
|
+ MPP28_GPIO, // Sys LED Green
|
|
+ MPP29_GPIO, // Sys LED Yellow
|
|
+ MPP41_GPIO, // SATA1 LED Green
|
|
+ MPP42_GPIO, // SATA1 LED Red
|
|
+ MPP12_GPO, // SATA2 LED Green
|
|
+ MPP13_GPIO, // SATA2 LED Red
|
|
+ MPP39_GPIO, // Copy LED Green
|
|
+ MPP40_GPIO, // Copy LED Red
|
|
+ MPP15_GPIO, // USB LED Green
|
|
+
|
|
+ MPP14_GPIO, // MCU Data
|
|
+ MPP16_GPIO, // MCU Clk
|
|
+ MPP17_GPIO, // MCU Act
|
|
+
|
|
+ MPP38_GPIO, // VID B0
|
|
+ MPP45_GPIO, // VID B1
|
|
+
|
|
+ MPP44_GPIO, // Buzzer
|
|
+ MPP43_GPIO, // HTP
|
|
+
|
|
+ MPP47_GPIO, // Power Resume Data
|
|
+ MPP49_GPIO, // Power Resume Clock
|
|
+
|
|
+ 0
|
|
+};
|
|
+
|
|
+static struct gpio_led nsa310_gpio_led[] = {
|
|
+ {
|
|
+ .name = "nsa310:green:System",
|
|
+ .default_trigger = "timer",
|
|
+ .gpio = 28,
|
|
+ .active_low = 0,
|
|
+
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:red:System",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 29,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:green:SATA1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 41,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:red:SATA1",
|
|
+ .default_trigger = "sata-disk",
|
|
+ .gpio = 42,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:green:SATA2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 12,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:red:SATA2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 13,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:green:USB",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 15,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:green:Copy",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 39,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "nsa310:red:Copy",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+
|
|
+static int nsa310_gpio_blink_set(unsigned gpio, int state,
|
|
+ unsigned long *delay_on, unsigned long *delay_off)
|
|
+{
|
|
+
|
|
+// Use hardware acceleration
|
|
+// if (delay_on && delay_off && !*delay_on && !*delay_off)
|
|
+// *delay_on = *delay_off = 100;
|
|
+
|
|
+ switch(state) {
|
|
+ case GPIO_LED_NO_BLINK_LOW:
|
|
+ case GPIO_LED_NO_BLINK_HIGH:
|
|
+ orion_gpio_set_blink(gpio, 0);
|
|
+ gpio_set_value(gpio, state);
|
|
+ break;
|
|
+ case GPIO_LED_BLINK:
|
|
+ orion_gpio_set_blink(gpio, 1);
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static struct gpio_led_platform_data nsa310_led_data = {
|
|
+ .leds = nsa310_gpio_led,
|
|
+ .num_leds = ARRAY_SIZE(nsa310_gpio_led),
|
|
+ .gpio_blink_set = nsa310_gpio_blink_set,
|
|
+};
|
|
+
|
|
+static struct platform_device nsa310_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = { .platform_data = &nsa310_led_data, }
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button nsa310_gpio_keys_button[] = {
|
|
+ {
|
|
+ .code = KEY_POWER,
|
|
+ .type = EV_KEY,
|
|
+ .gpio = 46,
|
|
+ .desc = "Power Button",
|
|
+ .active_low = 0,
|
|
+ .debounce_interval = 1000,
|
|
+ },
|
|
+ {
|
|
+ .code = KEY_COPY,
|
|
+ .type = EV_KEY,
|
|
+ .gpio = 37,
|
|
+ .desc = "USB Copy",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 1000,
|
|
+ },
|
|
+ {
|
|
+ .code = KEY_OPTION,
|
|
+ .type = EV_KEY,
|
|
+ .gpio = 36,
|
|
+ .desc = "Reset",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 1000,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data nsa310_keys_data = {
|
|
+ .buttons = nsa310_gpio_keys_button,
|
|
+ .nbuttons = ARRAY_SIZE(nsa310_gpio_keys_button),
|
|
+};
|
|
+
|
|
+
|
|
+static struct platform_device nsa310_buttons = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .dev = { .platform_data = &nsa310_keys_data, }
|
|
+};
|
|
+
|
|
+static void nsa310_power_off(void)
|
|
+{
|
|
+//
|
|
+//don't work with sysfs
|
|
+ printk(KERN_INFO "Activating power off GPIO pin...\n");
|
|
+ gpio_set_value(48, 1);
|
|
+
|
|
+// If machine goes to restart, uncomment next lines for infinite loop
|
|
+/* printk(KERN_INFO "System halted, please turn off power manually\n");
|
|
+ gpio_set_value(28, 0);
|
|
+ do {
|
|
+ mdelay(1000);
|
|
+ } while(1);
|
|
+*/
|
|
+}
|
|
+
|
|
+static void nsa310_timerfunc(unsigned long data)
|
|
+{
|
|
+// Activate USB Power
|
|
+ if (gpio_request(21, "USB Power") != 0 || gpio_direction_output(21, 1) != 0)
|
|
+ printk(KERN_ERR "failed to setup USB power GPIO\n");
|
|
+ else
|
|
+ printk(KERN_INFO "USB power enabled\n");
|
|
+ gpio_free(21);
|
|
+}
|
|
+
|
|
+static void __init nsa310_init(void)
|
|
+{
|
|
+ u32 dev, rev;
|
|
+
|
|
+ kirkwood_init();
|
|
+
|
|
+ kirkwood_mpp_conf(nsa310_mpp_config);
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(nsa310_nand_parts), 25);
|
|
+ kirkwood_ge00_init(&nsa310_ge00_data);
|
|
+ kirkwood_pcie_id(&dev, &rev);
|
|
+
|
|
+ kirkwood_sata_init(&nsa310_sata_data);
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_i2c_init();
|
|
+ i2c_register_board_info(0, &nsa310_i2c_rtc, 1);
|
|
+
|
|
+ platform_device_register(&nsa310_leds);
|
|
+ platform_device_register(&nsa310_buttons);
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+// USB Power delay for 20 sec
|
|
+ timer.function = nsa310_timerfunc;
|
|
+ timer.data = 0;
|
|
+ timer.expires = jiffies + msecs_to_jiffies(20000);
|
|
+ add_timer(&timer);
|
|
+
|
|
+
|
|
+/* Power resume control */
|
|
+ gpio_request(49, "Power-clk");
|
|
+ gpio_direction_output(49, 1);
|
|
+ gpio_request(47, "Power-data");
|
|
+// Clear power resume
|
|
+// gpio_direction_output(47, 0);
|
|
+// Set power resume
|
|
+ gpio_direction_output(47, 1);
|
|
+ udelay(1000);
|
|
+// gpio_direction_output(49, 0);
|
|
+ gpio_set_value(49, 0);
|
|
+// release GPIO?
|
|
+//test
|
|
+ gpio_free(47);
|
|
+ gpio_free(49);
|
|
+ printk(KERN_INFO "Power resume enabled\n");
|
|
+
|
|
+
|
|
+// Activate Power-off GPIO
|
|
+ if (gpio_request(48, "Power-off") == 0 && gpio_direction_output(48, 0) == 0) {
|
|
+// gpio_free(48);
|
|
+ pm_power_off = nsa310_power_off;
|
|
+ printk(KERN_INFO "Power-off GPIO enabled\n");
|
|
+ } else
|
|
+ printk(KERN_ERR "failed to configure Power-off GPIO\n");
|
|
+
|
|
+};
|
|
+
|
|
+static int __init nsa310_pci_init(void)
|
|
+{
|
|
+ if (machine_is_nsa310())
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+subsys_initcall(nsa310_pci_init);
|
|
+
|
|
+MACHINE_START(NSA310, "Zyxel NSA-310")
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = nsa310_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -rupN a/arch/arm/mach-kirkwood/nsa320-setup.c b/arch/arm/mach-kirkwood/nsa320-setup.c
|
|
--- a/arch/arm/mach-kirkwood/nsa320-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/nsa320-setup.c 2012-08-20 00:08:31.320824200 -0400
|
|
@@ -0,0 +1,308 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/nsa320-setup.c
|
|
+ *
|
|
+ * ZyXEL NSA320 2-Bay Power Media Server Setup
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mtd/nand.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/leds.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/nsa3xx-hwmon.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition nsa320_nand_parts[] = {
|
|
+ {
|
|
+ .name = "uboot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M,
|
|
+ .mask_flags = MTD_WRITEABLE
|
|
+ }, {
|
|
+ .name = "uboot_env",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_512K
|
|
+ }, {
|
|
+ .name = "key_store",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_512K
|
|
+ }, {
|
|
+ .name = "info",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_512K
|
|
+ }, {
|
|
+ .name = "etc",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 10 * SZ_1M
|
|
+ }, {
|
|
+ .name = "kernel_1",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 10 * SZ_1M
|
|
+ }, {
|
|
+ .name = "rootfs1",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 48 * SZ_1M - SZ_256K
|
|
+ }, {
|
|
+ .name = "kernel_2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 10 * SZ_1M
|
|
+ }, {
|
|
+ .name = "rootfs2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 48 * SZ_1M - SZ_256K
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct i2c_board_info __initdata nsa320_i2c_rtc = {
|
|
+ I2C_BOARD_INFO("pcf8563", 0x51),
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data nsa320_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(1),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data nsa320_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button nsa320_button_pins[] = {
|
|
+ {
|
|
+ .code = KEY_RESTART,
|
|
+ .gpio = 36,
|
|
+ .desc = "Reset",
|
|
+ .active_low = 1,
|
|
+ }, {
|
|
+ .code = KEY_COPY,
|
|
+ .gpio = 37,
|
|
+ .desc = "Copy",
|
|
+ .active_low = 1,
|
|
+ }, {
|
|
+ .code = KEY_POWER,
|
|
+ .gpio = 46,
|
|
+ .desc = "Power",
|
|
+ .active_low = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data nsa320_button_data = {
|
|
+ .buttons = nsa320_button_pins,
|
|
+ .nbuttons = ARRAY_SIZE(nsa320_button_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device nsa320_buttons = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &nsa320_button_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led nsa320_led_pins[] = {
|
|
+ {
|
|
+ .name = "nsa320:green:hdd2",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 12,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:red:hdd2",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 13,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:green:usb",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 15,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:green:sys",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 28,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:orange:sys",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 29,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:green:copy",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 39,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:red:copy",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 40,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:green:hdd1",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 41,
|
|
+ .active_low = 0,
|
|
+ }, {
|
|
+ .name = "nsa320:red:hdd1",
|
|
+ .default_trigger = "default-off",
|
|
+ .gpio = 42,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data nsa320_led_data = {
|
|
+ .leds = nsa320_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(nsa320_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device nsa320_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &nsa320_led_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct nsa3xx_hwmon_platform_data nsa320_hwmon_data = {
|
|
+ /* GPIOs connected to Holtek HT46R065 MCU */
|
|
+ .act_pin = 17,
|
|
+ .clk_pin = 16,
|
|
+ .data_pin = 14,
|
|
+};
|
|
+
|
|
+static struct platform_device nsa320_hwmon = {
|
|
+ .name = "nsa3xx-hwmon",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &nsa320_hwmon_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static unsigned int nsa320_mpp_config[] __initdata = {
|
|
+ MPP0_NF_IO2,
|
|
+ MPP1_NF_IO3,
|
|
+ MPP2_NF_IO4,
|
|
+ MPP3_NF_IO5,
|
|
+ MPP4_NF_IO6,
|
|
+ MPP5_NF_IO7,
|
|
+ MPP6_SYSRST_OUTn,
|
|
+ MPP7_GPO,
|
|
+ MPP8_TW0_SDA, /* PCF8563 RTC chip */
|
|
+ MPP9_TW0_SCK, /* connected to TWSI */
|
|
+ MPP10_UART0_TXD,
|
|
+ MPP11_UART0_RXD,
|
|
+ MPP12_GPO, /* HDD2 LED (green) */
|
|
+ MPP13_GPIO, /* HDD2 LED (red) */
|
|
+ MPP14_GPIO, /* MCU DATA pin (in) */
|
|
+ MPP15_GPIO, /* USB LED (green) */
|
|
+ MPP16_GPIO, /* MCU CLK pin (out) */
|
|
+ MPP17_GPIO, /* MCU ACT pin (out) */
|
|
+ MPP18_NF_IO0,
|
|
+ MPP19_NF_IO1,
|
|
+ MPP20_GPIO,
|
|
+ MPP21_GPIO, /* USB power */
|
|
+ MPP22_GPIO,
|
|
+ MPP23_GPIO,
|
|
+ MPP24_GPIO,
|
|
+ MPP25_GPIO,
|
|
+ MPP26_GPIO,
|
|
+ MPP27_GPIO,
|
|
+ MPP28_GPIO, /* SYS LED (green) */
|
|
+ MPP29_GPIO, /* SYS LED (orange) */
|
|
+ MPP30_GPIO,
|
|
+ MPP31_GPIO,
|
|
+ MPP32_GPIO,
|
|
+ MPP33_GPO,
|
|
+ MPP34_GPIO,
|
|
+ MPP35_GPIO,
|
|
+ MPP36_GPIO, /* reset button */
|
|
+ MPP37_GPIO, /* copy button */
|
|
+ MPP38_GPIO, /* VID B0 */
|
|
+ MPP39_GPIO, /* COPY LED (green) */
|
|
+ MPP40_GPIO, /* COPY LED (red) */
|
|
+ MPP41_GPIO, /* HDD1 LED (green) */
|
|
+ MPP42_GPIO, /* HDD1 LED (red) */
|
|
+ MPP43_GPIO, /* HTP pin */
|
|
+ MPP44_GPIO, /* buzzer */
|
|
+ MPP45_GPIO, /* VID B1 */
|
|
+ MPP46_GPIO, /* power button */
|
|
+ MPP47_GPIO, /* power resume data */
|
|
+ MPP48_GPIO, /* power off */
|
|
+ MPP49_GPIO, /* power resume clock */
|
|
+ 0
|
|
+};
|
|
+
|
|
+#define NSA320_GPIO_USB_POWER 21
|
|
+#define NSA320_GPIO_POWER_OFF 48
|
|
+
|
|
+static void nsa320_power_off(void)
|
|
+{
|
|
+ gpio_set_value(NSA320_GPIO_POWER_OFF, 1);
|
|
+}
|
|
+
|
|
+static int __initdata usb_power = 1; /* default "on" */
|
|
+
|
|
+static int __init nsa320_usb_power(char *str)
|
|
+{
|
|
+ usb_power = strncmp(str, "off", 3) ? 1 : 0;
|
|
+ return 1;
|
|
+}
|
|
+/* Parse boot_command_line string nsa320_usb_power=on|off */
|
|
+__setup("nsa320_usb_power=", nsa320_usb_power);
|
|
+
|
|
+static void __init nsa320_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(nsa320_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(nsa320_nand_parts), 40);
|
|
+
|
|
+ kirkwood_i2c_init();
|
|
+ i2c_register_board_info(0, &nsa320_i2c_rtc, 1);
|
|
+
|
|
+ if (gpio_request(NSA320_GPIO_USB_POWER, "USB Power Enable") ||
|
|
+ gpio_direction_output(NSA320_GPIO_USB_POWER, usb_power))
|
|
+ pr_err("nsa320: failed to configure USB power enable GPIO)\n");
|
|
+ gpio_free(NSA320_GPIO_USB_POWER);
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&nsa320_ge00_data);
|
|
+ kirkwood_sata_init(&nsa320_sata_data);
|
|
+ platform_device_register(&nsa320_leds);
|
|
+ platform_device_register(&nsa320_buttons);
|
|
+ platform_device_register(&nsa320_hwmon);
|
|
+
|
|
+ if (gpio_request(NSA320_GPIO_POWER_OFF, "power-off") ||
|
|
+ gpio_direction_output(NSA320_GPIO_POWER_OFF, 0))
|
|
+ pr_err("nsa320: failed to configure power-off GPIO\n");
|
|
+ else
|
|
+ pm_power_off = nsa320_power_off;
|
|
+}
|
|
+
|
|
+MACHINE_START(NSA320, "ZyXEL NSA320 2-Bay Power Media Server")
|
|
+ /* Maintainer: Peter Schildmann <linux@schildmann.info> */
|
|
+ .boot_params = 0x00000100,
|
|
+ .init_machine = nsa320_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+// .restart = kirkwood_restart,
|
|
+MACHINE_END
|
|
diff -rupN a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
|
--- a/drivers/hwmon/Kconfig 2011-10-24 03:10:05.000000000 -0400
|
|
+++ b/drivers/hwmon/Kconfig 2012-08-19 22:35:59.660852355 -0400
|
|
@@ -1327,6 +1327,19 @@ config SENSORS_MC13783_ADC
|
|
help
|
|
Support for the A/D converter on MC13783 PMIC.
|
|
|
|
+config SENSORS_NSA3XX
|
|
+ tristate "ZyXEL NSA3xx fan speed and temperature sensors"
|
|
+ depends on (MACH_NSA310 || MACH_NSA320) && GENERIC_GPIO
|
|
+ help
|
|
+ If you say yes here you get support for hardware monitoring
|
|
+ for the ZyXEL NSA3xx Media Servers.
|
|
+
|
|
+ The sensor data is taken from a Holtek HT46R065 microcontroller
|
|
+ conncted to GPIO lines.
|
|
+
|
|
+ This driver can also be built as a module. If so, the module
|
|
+ will be called nsa3xx-hwmon.
|
|
+
|
|
if ACPI
|
|
|
|
comment "ACPI drivers"
|
|
diff -rupN a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
|
|
--- a/drivers/hwmon/Makefile 2011-10-24 03:10:05.000000000 -0400
|
|
+++ b/drivers/hwmon/Makefile 2012-08-19 22:37:55.510821364 -0400
|
|
@@ -93,6 +93,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639
|
|
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
|
|
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
|
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
|
|
+obj-$(CONFIG_SENSORS_NSA3XX) += nsa3xx-hwmon.o
|
|
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
|
|
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
|
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
|
diff -rupN a/drivers/hwmon/nsa3xx-hwmon.c b/drivers/hwmon/nsa3xx-hwmon.c
|
|
--- a/drivers/hwmon/nsa3xx-hwmon.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/drivers/hwmon/nsa3xx-hwmon.c 2012-08-19 22:37:02.880821002 -0400
|
|
@@ -0,0 +1,251 @@
|
|
+/*
|
|
+ * drivers/hwmon/nsa3xx-hwmon.c
|
|
+ *
|
|
+ * ZyXEL NSA3xx Media Servers
|
|
+ * hardware monitoring
|
|
+ *
|
|
+ * Copyright (C) 2012 Peter Schildmann <linux@schildmann.info>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License v2 as published by the
|
|
+ * Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ * more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along with
|
|
+ * this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/hwmon.h>
|
|
+#include <linux/hwmon-sysfs.h>
|
|
+#include <linux/nsa3xx-hwmon.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <linux/delay.h>
|
|
+#include <asm/delay.h>
|
|
+
|
|
+#define MAGIC_NUMBER 0x55
|
|
+
|
|
+struct nsa3xx_hwmon {
|
|
+ struct platform_device *pdev;
|
|
+ struct device *classdev;
|
|
+ struct mutex update_lock; /* lock GPIO operations */
|
|
+ unsigned long last_updated; /* jiffies */
|
|
+ unsigned long mcu_data;
|
|
+};
|
|
+
|
|
+enum nsa3xx_inputs {
|
|
+ NSA3XX_FAN = 1,
|
|
+ NSA3XX_TEMP = 0,
|
|
+};
|
|
+
|
|
+static const char *nsa3xx_input_names[] = {
|
|
+ [NSA3XX_FAN] = "Chassis Fan",
|
|
+ [NSA3XX_TEMP] = "System Temperature",
|
|
+};
|
|
+
|
|
+static unsigned long nsa3xx_hwmon_update(struct device *dev)
|
|
+{
|
|
+ int i;
|
|
+ unsigned long mcu_data;
|
|
+ struct nsa3xx_hwmon *hwmon = dev_get_drvdata(dev);
|
|
+ struct nsa3xx_hwmon_platform_data *pdata = hwmon->pdev->dev.platform_data;
|
|
+
|
|
+ mutex_lock(&hwmon->update_lock);
|
|
+
|
|
+ mcu_data = hwmon->mcu_data;
|
|
+
|
|
+ if (time_after(jiffies, hwmon->last_updated + (3 * HZ)) || mcu_data == 0) {
|
|
+ dev_dbg(dev, "Reading MCU data\n");
|
|
+
|
|
+ gpio_set_value(pdata->act_pin, 0);
|
|
+ msleep(100);
|
|
+
|
|
+ for (i = 31; i >= 0; i--) {
|
|
+ gpio_set_value(pdata->clk_pin, 0);
|
|
+ udelay(100);
|
|
+
|
|
+ gpio_set_value(pdata->clk_pin, 1);
|
|
+ udelay(100);
|
|
+
|
|
+ mcu_data |= gpio_get_value(pdata->data_pin) ? (1 << i) : 0;
|
|
+ }
|
|
+
|
|
+ gpio_set_value(pdata->act_pin, 1);
|
|
+
|
|
+ if ((mcu_data & 0xff000000) != (MAGIC_NUMBER << 24)) {
|
|
+ dev_err(dev, "Failed to read MCU data\n");
|
|
+ mcu_data = 0;
|
|
+ }
|
|
+
|
|
+ hwmon->mcu_data = mcu_data;
|
|
+ hwmon->last_updated = jiffies;
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&hwmon->update_lock);
|
|
+
|
|
+ return mcu_data;
|
|
+}
|
|
+
|
|
+static ssize_t show_name(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "nsa3xx\n");
|
|
+}
|
|
+
|
|
+static ssize_t show_label(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ int channel = to_sensor_dev_attr(attr)->index;
|
|
+ return sprintf(buf, "%s\n", nsa3xx_input_names[channel]);
|
|
+}
|
|
+
|
|
+static ssize_t show_value(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ int channel = to_sensor_dev_attr(attr)->index;
|
|
+ unsigned long mcu_data = nsa3xx_hwmon_update(dev);
|
|
+ unsigned long value = 0;
|
|
+ switch(channel) {
|
|
+ case NSA3XX_TEMP:
|
|
+ value = (mcu_data & 0xffff) * 100;
|
|
+ break;
|
|
+ case NSA3XX_FAN:
|
|
+ value = ((mcu_data & 0xff0000) >> 16) * 100;
|
|
+ break;
|
|
+ }
|
|
+ return sprintf(buf, "%lu\n", value);
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
|
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, NSA3XX_TEMP);
|
|
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_value, NULL, NSA3XX_TEMP);
|
|
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, show_label, NULL, NSA3XX_FAN);
|
|
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_value, NULL, NSA3XX_FAN);
|
|
+
|
|
+static struct attribute *nsa3xx_attributes[] = {
|
|
+ &dev_attr_name.attr,
|
|
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
|
|
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
|
|
+ &sensor_dev_attr_fan1_label.dev_attr.attr,
|
|
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
|
|
+ NULL
|
|
+};
|
|
+
|
|
+static const struct attribute_group nsa3xx_attr_group = {
|
|
+ .attrs = nsa3xx_attributes,
|
|
+};
|
|
+
|
|
+static int nsa3xx_hwmon_request_gpios(struct nsa3xx_hwmon_platform_data *pdata)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if ((ret = gpio_request(pdata->act_pin, "act pin")))
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = gpio_request(pdata->clk_pin, "clk pin")))
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = gpio_request(pdata->data_pin, "data pin")))
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = gpio_direction_output(pdata->act_pin, 1)))
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = gpio_direction_output(pdata->clk_pin, 1)))
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = gpio_direction_input(pdata->data_pin)))
|
|
+ return ret;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void nsa3xx_hwmon_free_gpios(struct nsa3xx_hwmon_platform_data *pdata)
|
|
+{
|
|
+ gpio_free(pdata->act_pin);
|
|
+ gpio_free(pdata->clk_pin);
|
|
+ gpio_free(pdata->data_pin);
|
|
+}
|
|
+
|
|
+static int __devinit nsa3xx_hwmon_probe(struct platform_device *pdev)
|
|
+{
|
|
+ int ret;
|
|
+ struct nsa3xx_hwmon *hwmon;
|
|
+ struct nsa3xx_hwmon_platform_data *pdata = pdev->dev.platform_data;
|
|
+
|
|
+ hwmon = kzalloc(sizeof(struct nsa3xx_hwmon), GFP_KERNEL);
|
|
+ if (!hwmon)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ platform_set_drvdata(pdev, hwmon);
|
|
+ hwmon->pdev = pdev;
|
|
+ hwmon->mcu_data = 0;
|
|
+ mutex_init(&hwmon->update_lock);
|
|
+
|
|
+ ret = sysfs_create_group(&pdev->dev.kobj, &nsa3xx_attr_group);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ hwmon->classdev = hwmon_device_register(&pdev->dev);
|
|
+ if (IS_ERR(hwmon->classdev)) {
|
|
+ ret = PTR_ERR(hwmon->classdev);
|
|
+ goto err_sysfs;
|
|
+ }
|
|
+
|
|
+ ret = nsa3xx_hwmon_request_gpios(pdata);
|
|
+ if (ret)
|
|
+ goto err_free_gpio;
|
|
+
|
|
+ dev_info(&pdev->dev, "initialized\n");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_free_gpio:
|
|
+ nsa3xx_hwmon_free_gpios(pdata);
|
|
+ hwmon_device_unregister(hwmon->classdev);
|
|
+err_sysfs:
|
|
+ sysfs_remove_group(&pdev->dev.kobj, &nsa3xx_attr_group);
|
|
+err:
|
|
+ platform_set_drvdata(pdev, NULL);
|
|
+ kfree(hwmon);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int __devexit nsa3xx_hwmon_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct nsa3xx_hwmon *hwmon = platform_get_drvdata(pdev);
|
|
+
|
|
+ nsa3xx_hwmon_free_gpios(pdev->dev.platform_data);
|
|
+ hwmon_device_unregister(hwmon->classdev);
|
|
+ sysfs_remove_group(&pdev->dev.kobj, &nsa3xx_attr_group);
|
|
+ platform_set_drvdata(pdev, NULL);
|
|
+ kfree(hwmon);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct platform_driver nsa3xx_hwmon_driver = {
|
|
+ .probe = nsa3xx_hwmon_probe,
|
|
+ .remove = __devexit_p(nsa3xx_hwmon_remove),
|
|
+ .driver = {
|
|
+ .name = "nsa3xx-hwmon",
|
|
+ .owner = THIS_MODULE,
|
|
+ },
|
|
+};
|
|
+
|
|
+module_platform_driver(nsa3xx_hwmon_driver);
|
|
+
|
|
+MODULE_AUTHOR("Peter Schildmann <linux@schildmann.info>");
|
|
+MODULE_DESCRIPTION("NSA3XX Hardware Monitoring");
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS("platform:nsa3xx-hwmon");
|
|
diff -rupN a/include/linux/nsa3xx-hwmon.h b/include/linux/nsa3xx-hwmon.h
|
|
--- a/include/linux/nsa3xx-hwmon.h 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/include/linux/nsa3xx-hwmon.h 2012-08-19 22:30:03.460819876 -0400
|
|
@@ -0,0 +1,21 @@
|
|
+/*
|
|
+ * include/linux/nsa3xx.hwmon.h
|
|
+ *
|
|
+ * Platform data structure for ZyXEL NSA3xx hwmon driver
|
|
+ *
|
|
+ * This file is licensed under the terms of the GNU General Public
|
|
+ * License version 2. This program is licensed "as is" without any
|
|
+ * warranty of any kind, whether express or implied.
|
|
+ */
|
|
+
|
|
+#ifndef __LINUX_NSA3XX_HWMON_H
|
|
+#define __LINUX_NSA3XX_HWMON_H
|
|
+
|
|
+struct nsa3xx_hwmon_platform_data {
|
|
+ /* GPIO pins */
|
|
+ unsigned act_pin;
|
|
+ unsigned clk_pin;
|
|
+ unsigned data_pin;
|
|
+};
|
|
+
|
|
+#endif /* __LINUX_NSA3XX_HWMON_H */
|