|
@@ -1,2594 +0,0 @@
|
|
-/*
|
|
|
|
- * This file is part of stlc45xx
|
|
|
|
- *
|
|
|
|
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
- *
|
|
|
|
- * Contact: Kalle Valo <kalle.valo@nokia.com>
|
|
|
|
- *
|
|
|
|
- * This program is free software; you can redistribute it and/or
|
|
|
|
- * modify it under the terms of the GNU General Public License
|
|
|
|
- * version 2 as published by the Free Software Foundation.
|
|
|
|
- *
|
|
|
|
- * This program is distributed in the hope that it will be useful, but
|
|
|
|
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
- * General Public License for more details.
|
|
|
|
- *
|
|
|
|
- * You should have received a copy of the GNU General Public License
|
|
|
|
- * along with this program; if not, write to the Free Software
|
|
|
|
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
|
- * 02110-1301 USA
|
|
|
|
- *
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-#include "stlc45xx.h"
|
|
|
|
-
|
|
|
|
-#include <linux/module.h>
|
|
|
|
-#include <linux/platform_device.h>
|
|
|
|
-#include <linux/interrupt.h>
|
|
|
|
-#include <linux/firmware.h>
|
|
|
|
-#include <linux/delay.h>
|
|
|
|
-#include <linux/irq.h>
|
|
|
|
-#include <linux/spi/spi.h>
|
|
|
|
-#include <linux/etherdevice.h>
|
|
|
|
-#include <linux/gpio.h>
|
|
|
|
-#include <linux/moduleparam.h>
|
|
|
|
-
|
|
|
|
-#include "stlc45xx_lmac.h"
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * gpios should be handled in board files and provided via platform data,
|
|
|
|
- * but because it's currently impossible for stlc45xx to have a header file
|
|
|
|
- * in include/linux, let's use module paramaters for now
|
|
|
|
- */
|
|
|
|
-static int stlc45xx_gpio_power = 97;
|
|
|
|
-module_param(stlc45xx_gpio_power, int, 0444);
|
|
|
|
-MODULE_PARM_DESC(stlc45xx_gpio_power, "stlc45xx gpio number for power line");
|
|
|
|
-
|
|
|
|
-static int stlc45xx_gpio_irq = 87;
|
|
|
|
-module_param(stlc45xx_gpio_irq, int, 0444);
|
|
|
|
-MODULE_PARM_DESC(stlc45xx_gpio_irq, "stlc45xx gpio number for irq line");
|
|
|
|
-
|
|
|
|
-static const u8 default_cal_channels[] = {
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x09,
|
|
|
|
- 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10,
|
|
|
|
- 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xe0, 0x00, 0xe0, 0x00,
|
|
|
|
- 0xe0, 0x00, 0xe0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
|
|
|
|
- 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
|
|
|
|
- 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9,
|
|
|
|
- 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
|
|
|
|
- 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d,
|
|
|
|
- 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17,
|
|
|
|
- 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00,
|
|
|
|
- 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x71, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8,
|
|
|
|
- 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
|
|
|
|
- 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0,
|
|
|
|
- 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6,
|
|
|
|
- 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
|
|
|
|
- 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca,
|
|
|
|
- 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21,
|
|
|
|
- 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00,
|
|
|
|
- 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0,
|
|
|
|
- 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76,
|
|
|
|
- 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01,
|
|
|
|
- 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0,
|
|
|
|
- 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
|
|
|
|
- 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
|
|
|
|
- 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37,
|
|
|
|
- 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b,
|
|
|
|
- 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00,
|
|
|
|
- 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0,
|
|
|
|
- 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a,
|
|
|
|
- 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x09, 0x00, 0x00, 0xc9, 0xff,
|
|
|
|
- 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
|
|
|
|
- 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
|
|
|
|
- 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab,
|
|
|
|
- 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33,
|
|
|
|
- 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00,
|
|
|
|
- 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0,
|
|
|
|
- 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7,
|
|
|
|
- 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d,
|
|
|
|
- 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80,
|
|
|
|
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x80, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00,
|
|
|
|
- 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00,
|
|
|
|
- 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
|
|
|
|
- 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42,
|
|
|
|
- 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01,
|
|
|
|
- 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0,
|
|
|
|
- 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0,
|
|
|
|
- 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17,
|
|
|
|
- 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
|
|
|
|
- 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x09, 0x00, 0x00, 0xc9,
|
|
|
|
- 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01,
|
|
|
|
- 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
|
|
|
|
- 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01,
|
|
|
|
- 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0,
|
|
|
|
- 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb,
|
|
|
|
- 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21,
|
|
|
|
- 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
|
|
|
|
- 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0,
|
|
|
|
- 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
|
|
|
|
- 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x8a, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00,
|
|
|
|
- 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0,
|
|
|
|
- 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
|
|
|
|
- 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0,
|
|
|
|
- 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22,
|
|
|
|
- 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b,
|
|
|
|
- 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
|
|
|
|
- 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0,
|
|
|
|
- 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
|
|
|
|
- 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x09, 0x00, 0x00,
|
|
|
|
- 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10,
|
|
|
|
- 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
|
|
|
|
- 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54,
|
|
|
|
- 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33,
|
|
|
|
- 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
|
|
|
|
- 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0,
|
|
|
|
- 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
|
|
|
|
- 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c,
|
|
|
|
- 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00,
|
|
|
|
- 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
|
|
|
|
- 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0,
|
|
|
|
- 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42,
|
|
|
|
- 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
|
|
|
|
- 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0,
|
|
|
|
- 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
|
|
|
|
- 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d,
|
|
|
|
- 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
|
|
|
|
- 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x09, 0x00,
|
|
|
|
- 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01,
|
|
|
|
- 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
|
|
|
|
- 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
|
|
|
|
- 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
|
|
|
|
- 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0,
|
|
|
|
- 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc,
|
|
|
|
- 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
|
|
|
|
- 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54,
|
|
|
|
- 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00,
|
|
|
|
- 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
|
|
|
|
- 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06,
|
|
|
|
- 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96,
|
|
|
|
- 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x9e, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff,
|
|
|
|
- 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
|
|
|
|
- 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00,
|
|
|
|
- 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0,
|
|
|
|
- 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb,
|
|
|
|
- 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
|
|
|
|
- 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
|
|
|
|
- 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
|
|
|
|
- 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79,
|
|
|
|
- 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00,
|
|
|
|
- 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
|
|
|
|
- 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
|
|
|
|
- 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
|
|
|
- 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9,
|
|
|
|
- 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0,
|
|
|
|
- 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
|
|
|
|
- 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d,
|
|
|
|
- 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
|
|
|
|
- 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00 };
|
|
|
|
-
|
|
|
|
-static const u8 default_cal_rssi[] = {
|
|
|
|
- 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72,
|
|
|
|
- 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00,
|
|
|
|
- 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a,
|
|
|
|
- 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe,
|
|
|
|
- 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00,
|
|
|
|
- 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01,
|
|
|
|
- 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a,
|
|
|
|
- 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
-
|
|
|
|
-static void stlc45xx_tx_edcf(struct stlc45xx *stlc);
|
|
|
|
-static void stlc45xx_tx_setup(struct stlc45xx *stlc);
|
|
|
|
-static void stlc45xx_tx_scan(struct stlc45xx *stlc);
|
|
|
|
-static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable);
|
|
|
|
-static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave);
|
|
|
|
-static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave);
|
|
|
|
-
|
|
|
|
-static ssize_t stlc45xx_sysfs_show_cal_rssi(struct device *dev,
|
|
|
|
- struct device_attribute *attr,
|
|
|
|
- char *buf)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(dev);
|
|
|
|
- ssize_t len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- len = PAGE_SIZE;
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (stlc->cal_rssi)
|
|
|
|
- hex_dump_to_buffer(stlc->cal_rssi, RSSI_CAL_ARRAY_LEN, 16,
|
|
|
|
- 2, buf, len, 0);
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- len = strlen(buf);
|
|
|
|
-
|
|
|
|
- return len;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static ssize_t stlc45xx_sysfs_store_cal_rssi(struct device *dev,
|
|
|
|
- struct device_attribute *attr,
|
|
|
|
- const char *buf, size_t count)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(dev);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (count != RSSI_CAL_ARRAY_LEN) {
|
|
|
|
- stlc45xx_error("invalid cal_rssi length: %zu", count);
|
|
|
|
- count = 0;
|
|
|
|
- goto out_unlock;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- kfree(stlc->cal_rssi);
|
|
|
|
-
|
|
|
|
- stlc->cal_rssi = kmemdup(buf, RSSI_CAL_ARRAY_LEN, GFP_KERNEL);
|
|
|
|
-
|
|
|
|
- if (!stlc->cal_rssi) {
|
|
|
|
- stlc45xx_error("failed to allocate memory for cal_rssi");
|
|
|
|
- count = 0;
|
|
|
|
- goto out_unlock;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- out_unlock:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- return count;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static ssize_t stlc45xx_sysfs_show_cal_channels(struct device *dev,
|
|
|
|
- struct device_attribute *attr,
|
|
|
|
- char *buf)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(dev);
|
|
|
|
- ssize_t len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- len = PAGE_SIZE;
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (stlc->cal_channels)
|
|
|
|
- hex_dump_to_buffer(stlc->cal_channels, CHANNEL_CAL_ARRAY_LEN,
|
|
|
|
- 16, 2, buf, len, 0);
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- len = strlen(buf);
|
|
|
|
-
|
|
|
|
- return len;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static ssize_t stlc45xx_sysfs_store_cal_channels(struct device *dev,
|
|
|
|
- struct device_attribute *attr,
|
|
|
|
- const char *buf, size_t count)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(dev);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (count != CHANNEL_CAL_ARRAY_LEN) {
|
|
|
|
- stlc45xx_error("invalid cal_channels size: %zu ", count);
|
|
|
|
- count = 0;
|
|
|
|
- goto out_unlock;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- kfree(stlc->cal_channels);
|
|
|
|
-
|
|
|
|
- stlc->cal_channels = kmemdup(buf, count, GFP_KERNEL);
|
|
|
|
-
|
|
|
|
- if (!stlc->cal_channels) {
|
|
|
|
- stlc45xx_error("failed to allocate memory for cal_channels");
|
|
|
|
- count = 0;
|
|
|
|
- goto out_unlock;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-out_unlock:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- return count;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static ssize_t stlc45xx_sysfs_show_tx_buf(struct device *dev,
|
|
|
|
- struct device_attribute *attr,
|
|
|
|
- char *buf)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(dev);
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- ssize_t len = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
|
|
|
|
- len += sprintf(buf + len, "0x%x: 0x%x-0x%x\n",
|
|
|
|
- entry->handle, entry->start,
|
|
|
|
- entry->end);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- return len;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static DEVICE_ATTR(cal_rssi, S_IRUGO | S_IWUSR,
|
|
|
|
- stlc45xx_sysfs_show_cal_rssi,
|
|
|
|
- stlc45xx_sysfs_store_cal_rssi);
|
|
|
|
-static DEVICE_ATTR(cal_channels, S_IRUGO | S_IWUSR,
|
|
|
|
- stlc45xx_sysfs_show_cal_channels,
|
|
|
|
- stlc45xx_sysfs_store_cal_channels);
|
|
|
|
-static DEVICE_ATTR(tx_buf, S_IRUGO, stlc45xx_sysfs_show_tx_buf, NULL);
|
|
|
|
-
|
|
|
|
-static void stlc45xx_spi_read(struct stlc45xx *stlc, unsigned long addr,
|
|
|
|
- void *buf, size_t len)
|
|
|
|
-{
|
|
|
|
- struct spi_transfer t[2];
|
|
|
|
- struct spi_message m;
|
|
|
|
-
|
|
|
|
- /* We first push the address */
|
|
|
|
- addr = (addr << 8) | ADDR_READ_BIT_15;
|
|
|
|
-
|
|
|
|
- spi_message_init(&m);
|
|
|
|
- memset(t, 0, sizeof(t));
|
|
|
|
-
|
|
|
|
- t[0].tx_buf = &addr;
|
|
|
|
- t[0].len = 2;
|
|
|
|
- spi_message_add_tail(&t[0], &m);
|
|
|
|
-
|
|
|
|
- t[1].rx_buf = buf;
|
|
|
|
- t[1].len = len;
|
|
|
|
- spi_message_add_tail(&t[1], &m);
|
|
|
|
-
|
|
|
|
- spi_sync(stlc->spi, &m);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static void stlc45xx_spi_write(struct stlc45xx *stlc, unsigned long addr,
|
|
|
|
- void *buf, size_t len)
|
|
|
|
-{
|
|
|
|
- struct spi_transfer t[3];
|
|
|
|
- struct spi_message m;
|
|
|
|
- u16 last_word;
|
|
|
|
-
|
|
|
|
- /* We first push the address */
|
|
|
|
- addr = addr << 8;
|
|
|
|
-
|
|
|
|
- spi_message_init(&m);
|
|
|
|
- memset(t, 0, sizeof(t));
|
|
|
|
-
|
|
|
|
- t[0].tx_buf = &addr;
|
|
|
|
- t[0].len = 2;
|
|
|
|
- spi_message_add_tail(&t[0], &m);
|
|
|
|
-
|
|
|
|
- t[1].tx_buf = buf;
|
|
|
|
- t[1].len = len;
|
|
|
|
- spi_message_add_tail(&t[1], &m);
|
|
|
|
-
|
|
|
|
- if (len % 2) {
|
|
|
|
- last_word = ((u8 *)buf)[len - 1];
|
|
|
|
-
|
|
|
|
- t[2].tx_buf = &last_word;
|
|
|
|
- t[2].len = 2;
|
|
|
|
- spi_message_add_tail(&t[2], &m);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- spi_sync(stlc->spi, &m);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static u16 stlc45xx_read16(struct stlc45xx *stlc, unsigned long addr)
|
|
|
|
-{
|
|
|
|
- u16 val;
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
|
|
|
|
-
|
|
|
|
- return val;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static u32 stlc45xx_read32(struct stlc45xx *stlc, unsigned long addr)
|
|
|
|
-{
|
|
|
|
- u32 val;
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
|
|
|
|
-
|
|
|
|
- return val;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_write16(struct stlc45xx *stlc, unsigned long addr, u16 val)
|
|
|
|
-{
|
|
|
|
- stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_write32(struct stlc45xx *stlc, unsigned long addr, u32 val)
|
|
|
|
-{
|
|
|
|
- stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct stlc45xx_spi_reg {
|
|
|
|
- u16 address;
|
|
|
|
- u16 length;
|
|
|
|
- char *name;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static void stlc45xx_txbuffer_dump(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *txbuffer;
|
|
|
|
- char *buf, *pos;
|
|
|
|
- int buf_len, l, count;
|
|
|
|
-
|
|
|
|
- if (!(DEBUG_LEVEL & DEBUG_TXBUFFER))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
|
|
|
|
-
|
|
|
|
- buf_len = 500;
|
|
|
|
- buf = kmalloc(buf_len, GFP_ATOMIC);
|
|
|
|
- if (!buf)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- pos = buf;
|
|
|
|
- count = 0;
|
|
|
|
-
|
|
|
|
- list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
|
|
|
|
- l = snprintf(pos, buf_len, "0x%x-0x%x,",
|
|
|
|
- txbuffer->start, txbuffer->end);
|
|
|
|
- /* drop the null byte */
|
|
|
|
- pos += l;
|
|
|
|
- buf_len -= l;
|
|
|
|
- count++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (count == 0)
|
|
|
|
- *pos = '\0';
|
|
|
|
- else
|
|
|
|
- *--pos = '\0';
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: in buffer %d regions: %s",
|
|
|
|
- count, buf);
|
|
|
|
-
|
|
|
|
- kfree(buf);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static int stlc45xx_txbuffer_find(struct stlc45xx *stlc, size_t len)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *txbuffer;
|
|
|
|
- int pos;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
|
|
|
|
-
|
|
|
|
- pos = FIRMWARE_TXBUFFER_START;
|
|
|
|
-
|
|
|
|
- if (list_empty(&stlc->txbuffer))
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * the entries in txbuffer must be in the same order as they are in
|
|
|
|
- * the real buffer
|
|
|
|
- */
|
|
|
|
- list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
|
|
|
|
- if (pos + len < txbuffer->start)
|
|
|
|
- break;
|
|
|
|
- pos = ALIGN(txbuffer->end + 1, 4);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (pos + len > FIRMWARE_TXBUFFER_END)
|
|
|
|
- /* not enough room */
|
|
|
|
- pos = -1;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: find %zu B: 0x%x", len, pos);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return pos;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_txbuffer_add(struct stlc45xx *stlc,
|
|
|
|
- struct txbuffer *txbuffer)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *r, *prev = NULL;
|
|
|
|
-
|
|
|
|
- if (list_empty(&stlc->txbuffer)) {
|
|
|
|
- list_add(&txbuffer->buffer_list, &stlc->txbuffer);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- r = list_first_entry(&stlc->txbuffer, struct txbuffer, buffer_list);
|
|
|
|
-
|
|
|
|
- if (txbuffer->start < r->start) {
|
|
|
|
- /* add to the beginning of the list */
|
|
|
|
- list_add(&txbuffer->buffer_list, &stlc->txbuffer);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- prev = NULL;
|
|
|
|
- list_for_each_entry(r, &stlc->txbuffer, buffer_list) {
|
|
|
|
- /* skip first entry, we checked for that above */
|
|
|
|
- if (!prev) {
|
|
|
|
- prev = r;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* double-check overlaps */
|
|
|
|
- WARN_ON_ONCE(txbuffer->start >= r->start &&
|
|
|
|
- txbuffer->start <= r->end);
|
|
|
|
- WARN_ON_ONCE(txbuffer->end >= r->start &&
|
|
|
|
- txbuffer->end <= r->end);
|
|
|
|
-
|
|
|
|
- if (prev->end < txbuffer->start &&
|
|
|
|
- txbuffer->end < r->start) {
|
|
|
|
- /* insert at this spot */
|
|
|
|
- list_add_tail(&txbuffer->buffer_list, &r->buffer_list);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- prev = r;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* not found */
|
|
|
|
- list_add_tail(&txbuffer->buffer_list, &stlc->txbuffer);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static struct txbuffer *stlc45xx_txbuffer_alloc(struct stlc45xx *stlc,
|
|
|
|
- size_t frame_len)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *entry = NULL;
|
|
|
|
- size_t len;
|
|
|
|
- int pos;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
|
|
|
|
-
|
|
|
|
- len = FIRMWARE_TXBUFFER_HEADER + frame_len + FIRMWARE_TXBUFFER_TRAILER;
|
|
|
|
- pos = stlc45xx_txbuffer_find(stlc, len);
|
|
|
|
-
|
|
|
|
- if (pos < 0)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- WARN_ON_ONCE(pos + len > FIRMWARE_TXBUFFER_END);
|
|
|
|
- WARN_ON_ONCE(pos < FIRMWARE_TXBUFFER_START);
|
|
|
|
-
|
|
|
|
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
|
|
|
- entry->start = pos;
|
|
|
|
- entry->frame_start = pos + FIRMWARE_TXBUFFER_HEADER;
|
|
|
|
- entry->end = entry->start + len - 1;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: allocated 0x%x-0x%x",
|
|
|
|
- entry->start, entry->end);
|
|
|
|
-
|
|
|
|
- stlc45xx_txbuffer_add(stlc, entry);
|
|
|
|
-
|
|
|
|
- stlc45xx_txbuffer_dump(stlc);
|
|
|
|
-
|
|
|
|
- return entry;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static void stlc45xx_txbuffer_free(struct stlc45xx *stlc,
|
|
|
|
- struct txbuffer *txbuffer)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: freed 0x%x-0x%x",
|
|
|
|
- txbuffer->start, txbuffer->end);
|
|
|
|
-
|
|
|
|
- list_del(&txbuffer->buffer_list);
|
|
|
|
- kfree(txbuffer);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static int stlc45xx_wait_bit(struct stlc45xx *stlc, u16 reg, u32 mask,
|
|
|
|
- u32 expected)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- char buffer[4];
|
|
|
|
-
|
|
|
|
- for (i = 0; i < 2000; i++) {
|
|
|
|
- stlc45xx_spi_read(stlc, reg, buffer, sizeof(buffer));
|
|
|
|
- if (((*(u32 *)buffer) & mask) == expected)
|
|
|
|
- return 1;
|
|
|
|
- msleep(1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_request_firmware(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- const struct firmware *fw;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- /* FIXME: should driver use it's own struct device? */
|
|
|
|
- ret = request_firmware(&fw, "3826.arm", &stlc->spi->dev);
|
|
|
|
-
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("request_firmware() failed: %d", ret);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (fw->size % 4) {
|
|
|
|
- stlc45xx_error("firmware size is not multiple of 32bit: %zu",
|
|
|
|
- fw->size);
|
|
|
|
- return -EILSEQ; /* Illegal byte sequence */;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (fw->size < 1000) {
|
|
|
|
- stlc45xx_error("firmware is too small: %zu", fw->size);
|
|
|
|
- return -EILSEQ;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc->fw = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
|
|
|
- if (!stlc->fw) {
|
|
|
|
- stlc45xx_error("could not allocate memory for firmware");
|
|
|
|
- return -ENOMEM;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc->fw_len = fw->size;
|
|
|
|
-
|
|
|
|
- release_firmware(fw);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_upload_firmware(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct s_dma_regs dma_regs;
|
|
|
|
- unsigned long fw_len, fw_addr;
|
|
|
|
- long _fw_len;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- if (!stlc->fw) {
|
|
|
|
- ret = stlc45xx_request_firmware(stlc);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* stop the device */
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
|
|
|
|
- SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
|
|
|
|
- | SPI_CTRL_STAT_START_HALTED);
|
|
|
|
-
|
|
|
|
- msleep(TARGET_BOOT_SLEEP);
|
|
|
|
-
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
|
|
|
|
- SPI_CTRL_STAT_HOST_OVERRIDE
|
|
|
|
- | SPI_CTRL_STAT_START_HALTED);
|
|
|
|
-
|
|
|
|
- msleep(TARGET_BOOT_SLEEP);
|
|
|
|
-
|
|
|
|
- fw_addr = FIRMWARE_ADDRESS;
|
|
|
|
- fw_len = stlc->fw_len;
|
|
|
|
-
|
|
|
|
- while (fw_len > 0) {
|
|
|
|
- _fw_len = (fw_len > SPI_MAX_PACKET_SIZE)
|
|
|
|
- ? SPI_MAX_PACKET_SIZE : fw_len;
|
|
|
|
- dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
|
|
|
|
- dma_regs.len = cpu_to_le16(_fw_len);
|
|
|
|
- dma_regs.addr = cpu_to_le32(fw_addr);
|
|
|
|
-
|
|
|
|
- fw_len -= _fw_len;
|
|
|
|
- fw_addr += _fw_len;
|
|
|
|
-
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_CTRL, dma_regs.cmd);
|
|
|
|
-
|
|
|
|
- if (stlc45xx_wait_bit(stlc, SPI_ADRS_DMA_WRITE_CTRL,
|
|
|
|
- HOST_ALLOWED, HOST_ALLOWED) == 0) {
|
|
|
|
- stlc45xx_error("fw_upload not allowed to DMA write");
|
|
|
|
- return -EAGAIN;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_LEN, dma_regs.len);
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_DMA_WRITE_BASE, dma_regs.addr);
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, stlc->fw, _fw_len);
|
|
|
|
-
|
|
|
|
- /* FIXME: I think this doesn't work if firmware is large,
|
|
|
|
- * this loop goes to second round. fw->data is not
|
|
|
|
- * increased at all! */
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- BUG_ON(fw_len != 0);
|
|
|
|
-
|
|
|
|
- /* enable host interrupts */
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN, SPI_HOST_INTS_DEFAULT);
|
|
|
|
-
|
|
|
|
- /* boot the device */
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
|
|
|
|
- SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
|
|
|
|
- | SPI_CTRL_STAT_RAM_BOOT);
|
|
|
|
-
|
|
|
|
- msleep(TARGET_BOOT_SLEEP);
|
|
|
|
-
|
|
|
|
- stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
|
|
|
|
- SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT);
|
|
|
|
- msleep(TARGET_BOOT_SLEEP);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static void stlc45xx_check_txsent(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *entry, *n;
|
|
|
|
-
|
|
|
|
- list_for_each_entry_safe(entry, n, &stlc->tx_sent, tx_list) {
|
|
|
|
- if (time_after(jiffies, entry->lifetime)) {
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("frame 0x%x lifetime exceeded",
|
|
|
|
- entry->start);
|
|
|
|
- list_del(&entry->tx_list);
|
|
|
|
- skb_pull(entry->skb, entry->header_len);
|
|
|
|
- ieee80211_tx_status(stlc->hw, entry->skb);
|
|
|
|
- stlc45xx_txbuffer_free(stlc, entry);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_power_off(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
|
|
|
|
- gpio_set_value(stlc45xx_gpio_power, 0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_power_on(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- gpio_set_value(stlc45xx_gpio_power, 1);
|
|
|
|
- enable_irq(gpio_to_irq(stlc45xx_gpio_irq));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * need to wait a while before device can be accessed, the length
|
|
|
|
- * is just a guess
|
|
|
|
- */
|
|
|
|
- msleep(10);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold tx_lock */
|
|
|
|
-static void stlc45xx_flush_queues(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
-
|
|
|
|
- while (!list_empty(&stlc->tx_sent)) {
|
|
|
|
- entry = list_first_entry(&stlc->tx_sent,
|
|
|
|
- struct txbuffer, tx_list);
|
|
|
|
- list_del(&entry->tx_list);
|
|
|
|
- dev_kfree_skb(entry->skb);
|
|
|
|
- stlc45xx_txbuffer_free(stlc, entry);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- WARN_ON(!list_empty(&stlc->tx_sent));
|
|
|
|
-
|
|
|
|
- while (!list_empty(&stlc->tx_pending)) {
|
|
|
|
- entry = list_first_entry(&stlc->tx_pending,
|
|
|
|
- struct txbuffer, tx_list);
|
|
|
|
- list_del(&entry->tx_list);
|
|
|
|
- dev_kfree_skb(entry->skb);
|
|
|
|
- stlc45xx_txbuffer_free(stlc, entry);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- WARN_ON(!list_empty(&stlc->tx_pending));
|
|
|
|
- WARN_ON(!list_empty(&stlc->txbuffer));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_work_reset(struct work_struct *work)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = container_of(work, struct stlc45xx,
|
|
|
|
- work_reset);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (stlc->fw_state != FW_STATE_RESET)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- stlc45xx_power_off(stlc);
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- /* wait that all work_structs have finished, we can't hold
|
|
|
|
- * stlc->mutex to avoid deadlock */
|
|
|
|
- cancel_work_sync(&stlc->work);
|
|
|
|
-
|
|
|
|
- /* FIXME: find out good value to wait for chip power down */
|
|
|
|
- msleep(100);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- /* FIXME: we should gracefully handle if the state has changed
|
|
|
|
- * after re-acquiring mutex */
|
|
|
|
- WARN_ON(stlc->fw_state != FW_STATE_RESET);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
- stlc45xx_flush_queues(stlc);
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- stlc->fw_state = FW_STATE_RESETTING;
|
|
|
|
-
|
|
|
|
- stlc45xx_power_on(stlc);
|
|
|
|
- stlc45xx_upload_firmware(stlc);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold mutex */
|
|
|
|
-static void stlc45xx_reset(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- stlc45xx_warning("resetting firmware");
|
|
|
|
- stlc->fw_state = FW_STATE_RESET;
|
|
|
|
- ieee80211_stop_queues(stlc->hw);
|
|
|
|
- queue_work(stlc->hw->workqueue, &stlc->work_reset);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_work_tx_timeout(struct work_struct *work)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = container_of(work, struct stlc45xx,
|
|
|
|
- work_tx_timeout.work);
|
|
|
|
-
|
|
|
|
- stlc45xx_warning("tx timeout");
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (stlc->fw_state != FW_STATE_READY)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- stlc45xx_reset(stlc);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_int_ack(struct stlc45xx *stlc, u32 val)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_ACK, val);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_wakeup(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- unsigned long timeout;
|
|
|
|
- u32 ints;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- /* wake the chip */
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_WAKEUP);
|
|
|
|
-
|
|
|
|
- /* And wait for the READY interrupt */
|
|
|
|
- timeout = jiffies + HZ;
|
|
|
|
-
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- while (!(ints & SPI_HOST_INT_READY)) {
|
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
|
- goto out;
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_sleep(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_SLEEP);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_int_ready(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN,
|
|
|
|
- SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE);
|
|
|
|
-
|
|
|
|
- switch (stlc->fw_state) {
|
|
|
|
- case FW_STATE_BOOTING:
|
|
|
|
- stlc->fw_state = FW_STATE_READY;
|
|
|
|
- complete(&stlc->fw_comp);
|
|
|
|
- break;
|
|
|
|
- case FW_STATE_RESETTING:
|
|
|
|
- stlc->fw_state = FW_STATE_READY;
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_scan(stlc);
|
|
|
|
- stlc45xx_tx_setup(stlc);
|
|
|
|
- stlc45xx_tx_edcf(stlc);
|
|
|
|
-
|
|
|
|
- ieee80211_wake_queues(stlc->hw);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_rx_txack(struct stlc45xx *stlc, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_tx_info *info;
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct s_lmo_tx *tx;
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- int found = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- control = (struct s_lm_control *) skb->data;
|
|
|
|
- tx = (struct s_lmo_tx *) (control + 1);
|
|
|
|
-
|
|
|
|
- if (list_empty(&stlc->tx_sent)) {
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("no frames waiting for "
|
|
|
|
- "acknowledgement");
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
|
|
|
|
- if (control->handle == entry->handle) {
|
|
|
|
- found = 1;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!found) {
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("couldn't find frame for tx ack 0x%x",
|
|
|
|
- control->handle);
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TX, "TX ACK 0x%x", entry->handle);
|
|
|
|
-
|
|
|
|
- if (entry->status_needed) {
|
|
|
|
- info = IEEE80211_SKB_CB(entry->skb);
|
|
|
|
-
|
|
|
|
- if (!(tx->flags & LM_TX_FAILED)) {
|
|
|
|
- /* frame was acked */
|
|
|
|
- info->flags |= IEEE80211_TX_STAT_ACK;
|
|
|
|
- info->status.ack_signal = tx->rcpi / 2 - 110;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- skb_pull(entry->skb, entry->header_len);
|
|
|
|
-
|
|
|
|
- ieee80211_tx_status(stlc->hw, entry->skb);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list_del(&entry->tx_list);
|
|
|
|
-
|
|
|
|
- stlc45xx_check_txsent(stlc);
|
|
|
|
- if (list_empty(&stlc->tx_sent))
|
|
|
|
- /* there are no pending frames, we can stop the tx timeout
|
|
|
|
- * timer */
|
|
|
|
- cancel_delayed_work(&stlc->work_tx_timeout);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- stlc45xx_txbuffer_free(stlc, entry);
|
|
|
|
-
|
|
|
|
- if (stlc->tx_queue_stopped &&
|
|
|
|
- stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) != -1) {
|
|
|
|
- stlc45xx_debug(DEBUG_QUEUE, "room in tx buffer, waking queues");
|
|
|
|
- ieee80211_wake_queues(stlc->hw);
|
|
|
|
- stlc->tx_queue_stopped = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_rx_control(struct stlc45xx *stlc, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- control = (struct s_lm_control *) skb->data;
|
|
|
|
-
|
|
|
|
- switch (control->oid) {
|
|
|
|
- case LM_OID_TX:
|
|
|
|
- ret = stlc45xx_rx_txack(stlc, skb);
|
|
|
|
- break;
|
|
|
|
- case LM_OID_SETUP:
|
|
|
|
- case LM_OID_SCAN:
|
|
|
|
- case LM_OID_TRAP:
|
|
|
|
- case LM_OID_EDCF:
|
|
|
|
- case LM_OID_KEYCACHE:
|
|
|
|
- case LM_OID_PSM:
|
|
|
|
- case LM_OID_STATS:
|
|
|
|
- case LM_OID_LED:
|
|
|
|
- default:
|
|
|
|
- stlc45xx_warning("unhandled rx control oid %d\n",
|
|
|
|
- control->oid);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dev_kfree_skb(skb);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* copied from mac80211 */
|
|
|
|
-static void stlc45xx_parse_elems(u8 *start, size_t len,
|
|
|
|
- struct stlc45xx_ie_tim **tim,
|
|
|
|
- size_t *tim_len)
|
|
|
|
-{
|
|
|
|
- size_t left = len;
|
|
|
|
- u8 *pos = start;
|
|
|
|
-
|
|
|
|
- while (left >= 2) {
|
|
|
|
- u8 id, elen;
|
|
|
|
-
|
|
|
|
- id = *pos++;
|
|
|
|
- elen = *pos++;
|
|
|
|
- left -= 2;
|
|
|
|
-
|
|
|
|
- if (elen > left)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- switch (id) {
|
|
|
|
- case WLAN_EID_TIM:
|
|
|
|
- *tim = (struct stlc45xx_ie_tim *) pos;
|
|
|
|
- *tim_len = elen;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- left -= elen;
|
|
|
|
- pos += elen;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * mac80211 doesn't have support for asking frames with PS-Poll, so let's
|
|
|
|
- * implement in the driver for now. We have to add support to mac80211
|
|
|
|
- * later.
|
|
|
|
- */
|
|
|
|
-static int stlc45xx_check_more_data(struct stlc45xx *stlc, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
|
|
|
|
- struct ieee80211_hdr *hdr;
|
|
|
|
- size_t len;
|
|
|
|
- u16 fc;
|
|
|
|
-
|
|
|
|
- hdr = (void *) skb->data + sizeof(*data);
|
|
|
|
- len = skb->len - sizeof(*data);
|
|
|
|
-
|
|
|
|
- /* minimum frame length is the null frame length 24 bytes */
|
|
|
|
- if (len < 24) {
|
|
|
|
- stlc45xx_warning("invalid frame length when checking for "
|
|
|
|
- "more data");
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fc = le16_to_cpu(hdr->frame_control);
|
|
|
|
- if (!(fc & IEEE80211_FCTL_FROMDS))
|
|
|
|
- /* this is not from DS */
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- if (compare_ether_addr(hdr->addr1, stlc->mac_addr) != 0)
|
|
|
|
- /* the frame was not for us */
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- if (!(fc & IEEE80211_FCTL_MOREDATA)) {
|
|
|
|
- /* AP has no more frames buffered for us */
|
|
|
|
- stlc45xx_debug(DEBUG_PSM, "all buffered frames retrieved");
|
|
|
|
- stlc->pspolling = false;
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* MOREDATA bit is set, let's ask for a new frame from the AP */
|
|
|
|
- stlc45xx_tx_pspoll(stlc, stlc->psm);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * mac80211 cannot read TIM from beacons, so let's add a hack to the
|
|
|
|
- * driver. We have to add support to mac80211 later.
|
|
|
|
- */
|
|
|
|
-static int stlc45xx_rx_data_beacon(struct stlc45xx *stlc, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
|
|
|
|
- size_t len = skb->len, tim_len = 0, baselen, pvbmap_len;
|
|
|
|
- struct ieee80211_mgmt *mgmt;
|
|
|
|
- struct stlc45xx_ie_tim *tim = NULL;
|
|
|
|
- int bmap_offset, index, aid_bit;
|
|
|
|
-
|
|
|
|
- mgmt = (void *) skb->data + sizeof(*data);
|
|
|
|
-
|
|
|
|
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
|
|
|
|
- if (baselen > len) {
|
|
|
|
- stlc45xx_warning("invalid baselen in beacon");
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_parse_elems(mgmt->u.beacon.variable, len - baselen, &tim,
|
|
|
|
- &tim_len);
|
|
|
|
-
|
|
|
|
- if (!tim) {
|
|
|
|
- stlc45xx_warning("didn't find tim from a beacon");
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- bmap_offset = tim->bmap_control & 0xfe;
|
|
|
|
- index = stlc->aid / 8 - bmap_offset;
|
|
|
|
-
|
|
|
|
- pvbmap_len = tim_len - 3;
|
|
|
|
- if (index > pvbmap_len)
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
- aid_bit = !!(tim->pvbmap[index] & (1 << stlc->aid % 8));
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_PSM, "fc 0x%x duration %d seq %d dtim %u "
|
|
|
|
- "bmap_control 0x%x aid_bit %d",
|
|
|
|
- mgmt->frame_control, mgmt->duration, mgmt->seq_ctrl >> 4,
|
|
|
|
- tim->dtim_count, tim->bmap_control, aid_bit);
|
|
|
|
-
|
|
|
|
- if (!aid_bit)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- stlc->pspolling = true;
|
|
|
|
- stlc45xx_tx_pspoll(stlc, stlc->psm);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_rx_status status;
|
|
|
|
- struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
|
|
|
|
- int align = 0;
|
|
|
|
- u8 *p, align_len;
|
|
|
|
- u16 len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- if (stlc->psm) {
|
|
|
|
- if (data->flags & LM_IN_BEACON)
|
|
|
|
- stlc45xx_rx_data_beacon(stlc, skb);
|
|
|
|
- else if (stlc->pspolling && (data->flags & LM_IN_DATA))
|
|
|
|
- stlc45xx_check_more_data(stlc, skb);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- memset(&status, 0, sizeof(status));
|
|
|
|
-
|
|
|
|
- status.freq = data->frequency;
|
|
|
|
- status.signal = data->rcpi / 2 - 110;
|
|
|
|
-
|
|
|
|
- /* let's assume that maximum rcpi value is 140 (= 35 dBm) */
|
|
|
|
- status.qual = data->rcpi * 100 / 140;
|
|
|
|
-
|
|
|
|
- status.band = IEEE80211_BAND_2GHZ;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * FIXME: this gives warning from __ieee80211_rx()
|
|
|
|
- *
|
|
|
|
- * status.rate_idx = data->rate;
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- len = data->length;
|
|
|
|
-
|
|
|
|
- if (data->flags & LM_FLAG_ALIGN)
|
|
|
|
- align = 1;
|
|
|
|
-
|
|
|
|
- skb_pull(skb, sizeof(*data));
|
|
|
|
-
|
|
|
|
- if (align) {
|
|
|
|
- p = skb->data;
|
|
|
|
- align_len = *p;
|
|
|
|
- skb_pull(skb, align_len);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- skb_trim(skb, len);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
|
|
|
|
- stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
|
|
|
|
-
|
|
|
|
- memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
|
|
|
|
- ieee80211_rx(stlc->hw, skb);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static int stlc45xx_rx(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct sk_buff *skb;
|
|
|
|
- int ret;
|
|
|
|
- u16 len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_wakeup(stlc);
|
|
|
|
-
|
|
|
|
- /* dummy read to flush SPI DMA controller bug */
|
|
|
|
- stlc45xx_read16(stlc, SPI_ADRS_GEN_PURP_1);
|
|
|
|
-
|
|
|
|
- len = stlc45xx_read16(stlc, SPI_ADRS_DMA_DATA);
|
|
|
|
-
|
|
|
|
- if (len == 0) {
|
|
|
|
- stlc45xx_warning("rx request of zero bytes");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- skb = dev_alloc_skb(len);
|
|
|
|
- if (!skb) {
|
|
|
|
- stlc45xx_warning("could not alloc skb");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_read(stlc, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
|
|
|
|
-
|
|
|
|
- stlc45xx_sleep(stlc);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_RX, "rx frame 0x%p %d B", skb->data, skb->len);
|
|
|
|
- stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
|
|
|
|
-
|
|
|
|
- control = (struct s_lm_control *) skb->data;
|
|
|
|
-
|
|
|
|
- if (control->flags & LM_FLAG_CONTROL)
|
|
|
|
- ret = stlc45xx_rx_control(stlc, skb);
|
|
|
|
- else
|
|
|
|
- ret = stlc45xx_rx_data(stlc, skb);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static irqreturn_t stlc45xx_interrupt(int irq, void *config)
|
|
|
|
-{
|
|
|
|
- struct spi_device *spi = config;
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_IRQ, "IRQ");
|
|
|
|
-
|
|
|
|
- queue_work(stlc->hw->workqueue, &stlc->work);
|
|
|
|
-
|
|
|
|
- return IRQ_HANDLED;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_tx_frame(struct stlc45xx *stlc, u32 address,
|
|
|
|
- void *buf, size_t len)
|
|
|
|
-{
|
|
|
|
- struct s_dma_regs dma_regs;
|
|
|
|
- unsigned long timeout;
|
|
|
|
- int ret = 0;
|
|
|
|
- u32 ints;
|
|
|
|
-
|
|
|
|
- stlc->tx_frames++;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TX, "tx frame 0x%p %zu B", buf, len);
|
|
|
|
- stlc45xx_dump(DEBUG_TX_CONTENT, buf, len);
|
|
|
|
-
|
|
|
|
- stlc45xx_wakeup(stlc);
|
|
|
|
-
|
|
|
|
- dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
|
|
|
|
- dma_regs.len = cpu_to_le16(len);
|
|
|
|
- dma_regs.addr = cpu_to_le32(address);
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_write(stlc, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs,
|
|
|
|
- sizeof(dma_regs));
|
|
|
|
-
|
|
|
|
- stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, buf, len);
|
|
|
|
-
|
|
|
|
- timeout = jiffies + 2 * HZ;
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- while (!(ints & SPI_HOST_INT_WR_READY)) {
|
|
|
|
- if (time_after(jiffies, timeout)) {
|
|
|
|
- stlc45xx_warning("WR_READY timeout");
|
|
|
|
- ret = -1;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_int_ack(stlc, SPI_HOST_INT_WR_READY);
|
|
|
|
-
|
|
|
|
- stlc45xx_sleep(stlc);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_wq_tx(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- while (!list_empty(&stlc->tx_pending)) {
|
|
|
|
- entry = list_entry(stlc->tx_pending.next,
|
|
|
|
- struct txbuffer, tx_list);
|
|
|
|
-
|
|
|
|
- list_del_init(&entry->tx_list);
|
|
|
|
-
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- ret = stlc45xx_tx_frame(stlc, entry->frame_start,
|
|
|
|
- entry->skb->data, entry->skb->len);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- if (ret < 0) {
|
|
|
|
- /* frame transfer to firmware buffer failed */
|
|
|
|
- /* FIXME: report this to mac80211 */
|
|
|
|
- dev_kfree_skb(entry->skb);
|
|
|
|
- stlc45xx_txbuffer_free(stlc, entry);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list_add(&entry->tx_list, &stlc->tx_sent);
|
|
|
|
- queue_delayed_work(stlc->hw->workqueue,
|
|
|
|
- &stlc->work_tx_timeout,
|
|
|
|
- msecs_to_jiffies(TX_TIMEOUT));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_work(struct work_struct *work)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = container_of(work, struct stlc45xx, work);
|
|
|
|
- u32 ints;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (stlc->fw_state == FW_STATE_OFF &&
|
|
|
|
- stlc->fw_state == FW_STATE_RESET)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- stlc45xx_debug(DEBUG_BH, "begin host_ints 0x%08x", ints);
|
|
|
|
-
|
|
|
|
- if (ints & SPI_HOST_INT_READY) {
|
|
|
|
- stlc45xx_int_ready(stlc);
|
|
|
|
- stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (stlc->fw_state != FW_STATE_READY)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- if (ints & SPI_HOST_INT_UPDATE) {
|
|
|
|
- stlc45xx_int_ack(stlc, SPI_HOST_INT_UPDATE);
|
|
|
|
- ret = stlc45xx_rx(stlc);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_reset(stlc);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (ints & SPI_HOST_INT_SW_UPDATE) {
|
|
|
|
- stlc45xx_int_ack(stlc, SPI_HOST_INT_SW_UPDATE);
|
|
|
|
- ret = stlc45xx_rx(stlc);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_reset(stlc);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = stlc45xx_wq_tx(stlc);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_reset(stlc);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
|
|
|
|
- stlc45xx_debug(DEBUG_BH, "end host_ints 0x%08x", ints);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_tx_edcf(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct s_lmo_edcf *edcf;
|
|
|
|
- size_t len, edcf_len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- edcf_len = sizeof(*edcf);
|
|
|
|
- len = sizeof(*control) + edcf_len;
|
|
|
|
- control = kzalloc(len, GFP_KERNEL);
|
|
|
|
- edcf = (struct s_lmo_edcf *) (control + 1);
|
|
|
|
-
|
|
|
|
- control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
|
|
|
|
- control->length = edcf_len;
|
|
|
|
- control->oid = LM_OID_EDCF;
|
|
|
|
-
|
|
|
|
- edcf->slottime = 0x14;
|
|
|
|
- edcf->sifs = 10;
|
|
|
|
- edcf->eofpad = 6;
|
|
|
|
- edcf->maxburst = 1500;
|
|
|
|
-
|
|
|
|
- edcf->queues[0].aifs = 2;
|
|
|
|
- edcf->queues[0].pad0 = 1;
|
|
|
|
- edcf->queues[0].cwmin = 3;
|
|
|
|
- edcf->queues[0].cwmax = 7;
|
|
|
|
- edcf->queues[0].txop = 47;
|
|
|
|
- edcf->queues[1].aifs = 2;
|
|
|
|
- edcf->queues[1].pad0 = 0;
|
|
|
|
- edcf->queues[1].cwmin = 7;
|
|
|
|
- edcf->queues[1].cwmax = 15;
|
|
|
|
- edcf->queues[1].txop = 94;
|
|
|
|
- edcf->queues[2].aifs = 3;
|
|
|
|
- edcf->queues[2].pad0 = 0;
|
|
|
|
- edcf->queues[2].cwmin = 15;
|
|
|
|
- edcf->queues[2].cwmax = 1023;
|
|
|
|
- edcf->queues[2].txop = 0;
|
|
|
|
- edcf->queues[3].aifs = 7;
|
|
|
|
- edcf->queues[3].pad0 = 0;
|
|
|
|
- edcf->queues[3].cwmin = 15;
|
|
|
|
- edcf->queues[3].cwmax = 1023;
|
|
|
|
- edcf->queues[3].txop = 0;
|
|
|
|
- edcf->queues[4].aifs = 13;
|
|
|
|
- edcf->queues[4].pad0 = 99;
|
|
|
|
- edcf->queues[4].cwmin = 3437;
|
|
|
|
- edcf->queues[4].cwmax = 512;
|
|
|
|
- edcf->queues[4].txop = 12;
|
|
|
|
- edcf->queues[5].aifs = 142;
|
|
|
|
- edcf->queues[5].pad0 = 109;
|
|
|
|
- edcf->queues[5].cwmin = 8756;
|
|
|
|
- edcf->queues[5].cwmax = 6;
|
|
|
|
- edcf->queues[5].txop = 0;
|
|
|
|
- edcf->queues[6].aifs = 4;
|
|
|
|
- edcf->queues[6].pad0 = 0;
|
|
|
|
- edcf->queues[6].cwmin = 0;
|
|
|
|
- edcf->queues[6].cwmax = 58705;
|
|
|
|
- edcf->queues[6].txop = 25716;
|
|
|
|
- edcf->queues[7].aifs = 0;
|
|
|
|
- edcf->queues[7].pad0 = 0;
|
|
|
|
- edcf->queues[7].cwmin = 0;
|
|
|
|
- edcf->queues[7].cwmax = 0;
|
|
|
|
- edcf->queues[7].txop = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
|
|
|
|
-
|
|
|
|
- kfree(control);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_tx_setup(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct s_lmo_setup *setup;
|
|
|
|
- size_t len, setup_len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- setup_len = sizeof(*setup);
|
|
|
|
- len = sizeof(*control) + setup_len;
|
|
|
|
- control = kzalloc(len, GFP_KERNEL);
|
|
|
|
- setup = (struct s_lmo_setup *) (control + 1);
|
|
|
|
-
|
|
|
|
- control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
|
|
|
|
- control->length = setup_len;
|
|
|
|
- control->oid = LM_OID_SETUP;
|
|
|
|
-
|
|
|
|
- setup->flags = LM_SETUP_INFRA;
|
|
|
|
- setup->antenna = 2;
|
|
|
|
- setup->rx_align = 0;
|
|
|
|
- setup->rx_buffer = FIRMWARE_RXBUFFER_START;
|
|
|
|
- setup->rx_mtu = FIRMWARE_MTU;
|
|
|
|
- setup->frontend = 5;
|
|
|
|
- setup->timeout = 0;
|
|
|
|
- setup->truncate = 48896;
|
|
|
|
- setup->bratemask = 0xffffffff;
|
|
|
|
- setup->ref_clock = 644245094;
|
|
|
|
- setup->lpf_bandwidth = 65535;
|
|
|
|
- setup->osc_start_delay = 65535;
|
|
|
|
-
|
|
|
|
- memcpy(setup->macaddr, stlc->mac_addr, ETH_ALEN);
|
|
|
|
- memcpy(setup->bssid, stlc->bssid, ETH_ALEN);
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
|
|
|
|
-
|
|
|
|
- kfree(control);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_tx_scan(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct s_lmo_scan *scan;
|
|
|
|
- size_t len, scan_len;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- scan_len = sizeof(*scan);
|
|
|
|
- len = sizeof(*control) + scan_len;
|
|
|
|
- control = kzalloc(len, GFP_KERNEL);
|
|
|
|
- scan = (struct s_lmo_scan *) (control + 1);
|
|
|
|
-
|
|
|
|
- control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
|
|
|
|
- control->length = scan_len;
|
|
|
|
- control->oid = LM_OID_SCAN;
|
|
|
|
-
|
|
|
|
- scan->flags = LM_SCAN_EXIT;
|
|
|
|
- scan->bratemask = 0x15f;
|
|
|
|
- scan->aloft[0] = 3;
|
|
|
|
- scan->aloft[1] = 3;
|
|
|
|
- scan->aloft[2] = 1;
|
|
|
|
- scan->aloft[3] = 0;
|
|
|
|
- scan->aloft[4] = 0;
|
|
|
|
- scan->aloft[5] = 0;
|
|
|
|
- scan->aloft[6] = 0;
|
|
|
|
- scan->aloft[7] = 0;
|
|
|
|
-
|
|
|
|
- memcpy(&scan->rssical, &stlc->cal_rssi[(stlc->channel - 1) *
|
|
|
|
- RSSI_CAL_LEN],
|
|
|
|
- RSSI_CAL_LEN);
|
|
|
|
- memcpy(&scan->channel, &stlc->cal_channels[(stlc->channel - 1) *
|
|
|
|
- CHANNEL_CAL_LEN],
|
|
|
|
- CHANNEL_CAL_LEN);
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
|
|
|
|
-
|
|
|
|
- kfree(control);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * caller must hold mutex
|
|
|
|
- */
|
|
|
|
-static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_hdr *pspoll;
|
|
|
|
- int payload_len, padding, i;
|
|
|
|
- struct s_lm_data_out *data;
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- struct sk_buff *skb;
|
|
|
|
- char *payload;
|
|
|
|
- u16 fc;
|
|
|
|
-
|
|
|
|
- skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 16);
|
|
|
|
- if (!skb) {
|
|
|
|
- stlc45xx_warning("failed to allocate pspoll frame");
|
|
|
|
- return -ENOMEM;
|
|
|
|
- }
|
|
|
|
- skb_reserve(skb, stlc->hw->extra_tx_headroom);
|
|
|
|
-
|
|
|
|
- pspoll = (struct ieee80211_hdr *) skb_put(skb, 16);
|
|
|
|
- memset(pspoll, 0, 16);
|
|
|
|
- fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL;
|
|
|
|
- if (powersave)
|
|
|
|
- fc |= IEEE80211_FCTL_PM;
|
|
|
|
- pspoll->frame_control = cpu_to_le16(fc);
|
|
|
|
- pspoll->duration_id = cpu_to_le16(stlc->aid);
|
|
|
|
-
|
|
|
|
- /* aid in PS-Poll has its two MSBs each set to 1 */
|
|
|
|
- pspoll->duration_id |= cpu_to_le16(1 << 15) | cpu_to_le16(1 << 14);
|
|
|
|
-
|
|
|
|
- memcpy(pspoll->addr1, stlc->bssid, ETH_ALEN);
|
|
|
|
- memcpy(pspoll->addr2, stlc->mac_addr, ETH_ALEN);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_PSM, "sending PS-Poll frame to %pM (powersave %d, "
|
|
|
|
- "fc 0x%x, aid %d)", pspoll->addr1,
|
|
|
|
- powersave, fc, stlc->aid);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
|
|
|
|
-
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- if (!entry) {
|
|
|
|
- /*
|
|
|
|
- * The queue should be stopped before the firmware buffer
|
|
|
|
- * is full, so firmware buffer should always have enough
|
|
|
|
- * space.
|
|
|
|
- *
|
|
|
|
- * But I'm too lazy and omit it for now.
|
|
|
|
- */
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("firmware tx buffer full is full "
|
|
|
|
- "for null frame");
|
|
|
|
- return -ENOSPC;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- payload = skb->data;
|
|
|
|
- payload_len = skb->len;
|
|
|
|
- padding = (int) (skb->data - sizeof(*data)) & 3;
|
|
|
|
- entry->header_len = sizeof(*data) + padding;
|
|
|
|
-
|
|
|
|
- entry->skb = skb;
|
|
|
|
- entry->status_needed = false;
|
|
|
|
- entry->handle = (u32) skb;
|
|
|
|
- entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
|
|
|
|
- "padding %d header_len %d)",
|
|
|
|
- entry->handle, payload, payload_len, padding,
|
|
|
|
- entry->header_len);
|
|
|
|
- stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
|
|
|
|
-
|
|
|
|
- data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
|
|
|
|
-
|
|
|
|
- memset(data, 0, entry->header_len);
|
|
|
|
-
|
|
|
|
- if (padding)
|
|
|
|
- data->flags = LM_FLAG_ALIGN;
|
|
|
|
-
|
|
|
|
- data->flags = LM_OUT_BURST;
|
|
|
|
- data->length = payload_len;
|
|
|
|
- data->handle = entry->handle;
|
|
|
|
- data->aid = 1;
|
|
|
|
- data->rts_retries = 7;
|
|
|
|
- data->retries = 7;
|
|
|
|
- data->aloft_ctrl = 0;
|
|
|
|
- data->crypt_offset = 58;
|
|
|
|
- data->keytype = 0;
|
|
|
|
- data->keylen = 0;
|
|
|
|
- data->queue = LM_QUEUE_DATA3;
|
|
|
|
- data->backlog = 32;
|
|
|
|
- data->antenna = 2;
|
|
|
|
- data->cts = 3;
|
|
|
|
- data->power = 127;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < 8; i++)
|
|
|
|
- data->aloft[i] = 0;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * check if there's enough space in tx buffer
|
|
|
|
- *
|
|
|
|
- * FIXME: ignored for now
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
|
|
|
|
-
|
|
|
|
- list_add(&entry->tx_list, &stlc->tx_sent);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * caller must hold mutex
|
|
|
|
- *
|
|
|
|
- * shamelessly stolen from mac80211/ieee80211_send_nullfunc
|
|
|
|
- */
|
|
|
|
-static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_hdr *nullfunc;
|
|
|
|
- int payload_len, padding, i;
|
|
|
|
- struct s_lm_data_out *data;
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- struct sk_buff *skb;
|
|
|
|
- char *payload;
|
|
|
|
- u16 fc;
|
|
|
|
-
|
|
|
|
- skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 24);
|
|
|
|
- if (!skb) {
|
|
|
|
- stlc45xx_warning("failed to allocate buffer for null frame\n");
|
|
|
|
- return -ENOMEM;
|
|
|
|
- }
|
|
|
|
- skb_reserve(skb, stlc->hw->extra_tx_headroom);
|
|
|
|
-
|
|
|
|
- nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
|
|
|
|
- memset(nullfunc, 0, 24);
|
|
|
|
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
|
|
|
|
- IEEE80211_FCTL_TODS;
|
|
|
|
-
|
|
|
|
- if (powersave)
|
|
|
|
- fc |= IEEE80211_FCTL_PM;
|
|
|
|
-
|
|
|
|
- nullfunc->frame_control = cpu_to_le16(fc);
|
|
|
|
- memcpy(nullfunc->addr1, stlc->bssid, ETH_ALEN);
|
|
|
|
- memcpy(nullfunc->addr2, stlc->mac_addr, ETH_ALEN);
|
|
|
|
- memcpy(nullfunc->addr3, stlc->bssid, ETH_ALEN);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_PSM, "sending Null frame to %pM (powersave %d, "
|
|
|
|
- "fc 0x%x)", nullfunc->addr1, powersave, fc);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
|
|
|
|
-
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- if (!entry) {
|
|
|
|
- /*
|
|
|
|
- * The queue should be stopped before the firmware buffer
|
|
|
|
- * is full, so firmware buffer should always have enough
|
|
|
|
- * space.
|
|
|
|
- *
|
|
|
|
- * But I'm too lazy and omit it for now.
|
|
|
|
- */
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("firmware tx buffer full is full "
|
|
|
|
- "for null frame");
|
|
|
|
- return -ENOSPC;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- payload = skb->data;
|
|
|
|
- payload_len = skb->len;
|
|
|
|
- padding = (int) (skb->data - sizeof(*data)) & 3;
|
|
|
|
- entry->header_len = sizeof(*data) + padding;
|
|
|
|
-
|
|
|
|
- entry->skb = skb;
|
|
|
|
- entry->status_needed = false;
|
|
|
|
- entry->handle = (u32) skb;
|
|
|
|
- entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
|
|
|
|
- "padding %d header_len %d)",
|
|
|
|
- entry->handle, payload, payload_len, padding,
|
|
|
|
- entry->header_len);
|
|
|
|
- stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
|
|
|
|
-
|
|
|
|
- data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
|
|
|
|
-
|
|
|
|
- memset(data, 0, entry->header_len);
|
|
|
|
-
|
|
|
|
- if (padding)
|
|
|
|
- data->flags = LM_FLAG_ALIGN;
|
|
|
|
-
|
|
|
|
- data->flags = LM_OUT_BURST;
|
|
|
|
- data->length = payload_len;
|
|
|
|
- data->handle = entry->handle;
|
|
|
|
- data->aid = 1;
|
|
|
|
- data->rts_retries = 7;
|
|
|
|
- data->retries = 7;
|
|
|
|
- data->aloft_ctrl = 0;
|
|
|
|
- data->crypt_offset = 58;
|
|
|
|
- data->keytype = 0;
|
|
|
|
- data->keylen = 0;
|
|
|
|
- data->queue = LM_QUEUE_DATA3;
|
|
|
|
- data->backlog = 32;
|
|
|
|
- data->antenna = 2;
|
|
|
|
- data->cts = 3;
|
|
|
|
- data->power = 127;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < 8; i++)
|
|
|
|
- data->aloft[i] = 0;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * check if there's enough space in tx buffer
|
|
|
|
- *
|
|
|
|
- * FIXME: ignored for now
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
|
|
|
|
-
|
|
|
|
- list_add(&entry->tx_list, &stlc->tx_sent);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* caller must hold mutex */
|
|
|
|
-static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable)
|
|
|
|
-{
|
|
|
|
- struct s_lm_control *control;
|
|
|
|
- struct s_lmo_psm *psm;
|
|
|
|
- size_t len, psm_len;
|
|
|
|
-
|
|
|
|
- WARN_ON(!stlc->associated);
|
|
|
|
- WARN_ON(stlc->aid < 1);
|
|
|
|
- WARN_ON(stlc->aid > 2007);
|
|
|
|
-
|
|
|
|
- psm_len = sizeof(*psm);
|
|
|
|
- len = sizeof(*control) + psm_len;
|
|
|
|
- control = kzalloc(len, GFP_KERNEL);
|
|
|
|
- psm = (struct s_lmo_psm *) (control + 1);
|
|
|
|
-
|
|
|
|
- control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
|
|
|
|
- control->length = psm_len;
|
|
|
|
- control->oid = LM_OID_PSM;
|
|
|
|
-
|
|
|
|
- if (enable)
|
|
|
|
- psm->flags |= LM_PSM;
|
|
|
|
-
|
|
|
|
- psm->aid = stlc->aid;
|
|
|
|
-
|
|
|
|
- psm->beacon_rcpi_skip_max = 60;
|
|
|
|
-
|
|
|
|
- psm->intervals[0].interval = 1;
|
|
|
|
- psm->intervals[0].periods = 1;
|
|
|
|
- psm->intervals[1].interval = 1;
|
|
|
|
- psm->intervals[1].periods = 1;
|
|
|
|
- psm->intervals[2].interval = 1;
|
|
|
|
- psm->intervals[2].periods = 1;
|
|
|
|
- psm->intervals[3].interval = 1;
|
|
|
|
- psm->intervals[3].periods = 1;
|
|
|
|
-
|
|
|
|
- psm->nr = 0;
|
|
|
|
- psm->exclude[0] = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_PSM, "sending LM_OID_PSM (aid %d, interval %d)",
|
|
|
|
- psm->aid, psm->intervals[0].interval);
|
|
|
|
-
|
|
|
|
- stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
|
|
|
|
-
|
|
|
|
- kfree(control);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
- struct ieee80211_tx_info *info;
|
|
|
|
- struct ieee80211_rate *rate;
|
|
|
|
- int payload_len, padding, i;
|
|
|
|
- struct s_lm_data_out *data;
|
|
|
|
- struct txbuffer *entry;
|
|
|
|
- char *payload;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
|
|
|
|
- if (!entry) {
|
|
|
|
- /* the queue should be stopped before the firmware buffer
|
|
|
|
- * is full, so firmware buffer should always have enough
|
|
|
|
- * space */
|
|
|
|
- if (net_ratelimit())
|
|
|
|
- stlc45xx_warning("firmware buffer full");
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
- return NETDEV_TX_BUSY;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- info = IEEE80211_SKB_CB(skb);
|
|
|
|
-
|
|
|
|
- payload = skb->data;
|
|
|
|
- payload_len = skb->len;
|
|
|
|
- padding = (int) (skb->data - sizeof(*data)) & 3;
|
|
|
|
- entry->header_len = sizeof(*data) + padding;
|
|
|
|
-
|
|
|
|
- entry->skb = skb;
|
|
|
|
- entry->status_needed = true;
|
|
|
|
- entry->handle = (u32) skb;
|
|
|
|
- entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
|
|
|
|
- "padding %d header_len %d)",
|
|
|
|
- entry->handle, payload, payload_len, padding,
|
|
|
|
- entry->header_len);
|
|
|
|
- stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
|
|
|
|
-
|
|
|
|
- data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
|
|
|
|
-
|
|
|
|
- memset(data, 0, entry->header_len);
|
|
|
|
-
|
|
|
|
- if (padding)
|
|
|
|
- data->flags = LM_FLAG_ALIGN;
|
|
|
|
-
|
|
|
|
- data->flags = LM_OUT_BURST;
|
|
|
|
- data->length = payload_len;
|
|
|
|
- data->handle = entry->handle;
|
|
|
|
- data->aid = 1;
|
|
|
|
- data->rts_retries = 7;
|
|
|
|
- data->retries = 7;
|
|
|
|
- data->aloft_ctrl = 0;
|
|
|
|
- data->crypt_offset = 58;
|
|
|
|
- data->keytype = 0;
|
|
|
|
- data->keylen = 0;
|
|
|
|
- data->queue = 2;
|
|
|
|
- data->backlog = 32;
|
|
|
|
- data->antenna = 2;
|
|
|
|
- data->cts = 3;
|
|
|
|
- data->power = 127;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < 8; i++) {
|
|
|
|
- rate = ieee80211_get_tx_rate(stlc->hw, info);
|
|
|
|
- data->aloft[i] = rate->hw_value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list_add_tail(&entry->tx_list, &stlc->tx_pending);
|
|
|
|
-
|
|
|
|
- /* check if there's enough space in tx buffer */
|
|
|
|
- if (stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) == -1) {
|
|
|
|
- stlc45xx_debug(DEBUG_QUEUE, "tx buffer full, stopping queues");
|
|
|
|
- stlc->tx_queue_stopped = 1;
|
|
|
|
- ieee80211_stop_queues(stlc->hw);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- queue_work(stlc->hw->workqueue, &stlc->work);
|
|
|
|
-
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- return NETDEV_TX_OK;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_op_start(struct ieee80211_hw *hw)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
- unsigned long timeout;
|
|
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- stlc->fw_state = FW_STATE_BOOTING;
|
|
|
|
- stlc->channel = 1;
|
|
|
|
-
|
|
|
|
- stlc45xx_power_on(stlc);
|
|
|
|
-
|
|
|
|
- ret = stlc45xx_upload_firmware(stlc);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_power_off(stlc);
|
|
|
|
- goto out_unlock;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc->tx_queue_stopped = 0;
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- timeout = msecs_to_jiffies(2000);
|
|
|
|
- timeout = wait_for_completion_interruptible_timeout(&stlc->fw_comp,
|
|
|
|
- timeout);
|
|
|
|
- if (!timeout) {
|
|
|
|
- stlc45xx_error("firmware boot failed");
|
|
|
|
- stlc45xx_power_off(stlc);
|
|
|
|
- ret = -1;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_BOOT, "firmware booted");
|
|
|
|
-
|
|
|
|
- /* FIXME: should we take mutex just after wait_for_completion()? */
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- WARN_ON(stlc->fw_state != FW_STATE_READY);
|
|
|
|
-
|
|
|
|
-out_unlock:
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_op_stop(struct ieee80211_hw *hw)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- WARN_ON(stlc->fw_state != FW_STATE_READY);
|
|
|
|
-
|
|
|
|
- stlc45xx_power_off(stlc);
|
|
|
|
-
|
|
|
|
- /* FIXME: make sure that all work_structs have completed */
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&stlc->tx_lock);
|
|
|
|
- stlc45xx_flush_queues(stlc);
|
|
|
|
- spin_unlock_bh(&stlc->tx_lock);
|
|
|
|
-
|
|
|
|
- stlc->fw_state = FW_STATE_OFF;
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_op_add_interface(struct ieee80211_hw *hw,
|
|
|
|
- struct ieee80211_if_init_conf *conf)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- switch (conf->type) {
|
|
|
|
- case NL80211_IFTYPE_STATION:
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- return -EOPNOTSUPP;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- memcpy(stlc->mac_addr, conf->mac_addr, ETH_ALEN);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw,
|
|
|
|
- struct ieee80211_if_init_conf *conf)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- stlc->channel = hw->conf.channel->hw_value;
|
|
|
|
- stlc45xx_tx_scan(stlc);
|
|
|
|
- stlc45xx_tx_setup(stlc);
|
|
|
|
- stlc45xx_tx_edcf(stlc);
|
|
|
|
-
|
|
|
|
- if ((hw->conf.flags & IEEE80211_CONF_PS) != stlc->psm) {
|
|
|
|
- stlc->psm = hw->conf.flags & IEEE80211_CONF_PS;
|
|
|
|
- if (stlc->associated) {
|
|
|
|
- stlc45xx_tx_psm(stlc, stlc->psm);
|
|
|
|
- stlc45xx_tx_nullfunc(stlc, stlc->psm);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_op_configure_filter(struct ieee80211_hw *hw,
|
|
|
|
- unsigned int changed_flags,
|
|
|
|
- unsigned int *total_flags,
|
|
|
|
- int mc_count,
|
|
|
|
- struct dev_addr_list *mc_list)
|
|
|
|
-{
|
|
|
|
- *total_flags = 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
|
- struct ieee80211_vif *vif,
|
|
|
|
- struct ieee80211_bss_conf *info,
|
|
|
|
- u32 changed)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = hw->priv;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
- mutex_lock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- memcpy(stlc->bssid, info->bssid, ETH_ALEN);
|
|
|
|
- stlc45xx_tx_setup(stlc);
|
|
|
|
-
|
|
|
|
- mutex_unlock(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- if (changed & BSS_CHANGED_ASSOC) {
|
|
|
|
- stlc->associated = info->assoc;
|
|
|
|
- if (info->assoc)
|
|
|
|
- stlc->aid = info->aid;
|
|
|
|
- else
|
|
|
|
- stlc->aid = -1;
|
|
|
|
-
|
|
|
|
- if (stlc->psm) {
|
|
|
|
- stlc45xx_tx_psm(stlc, stlc->psm);
|
|
|
|
- stlc45xx_tx_nullfunc(stlc, stlc->psm);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/* can't be const, mac80211 writes to this */
|
|
|
|
-static struct ieee80211_rate stlc45xx_rates[] = {
|
|
|
|
- { .bitrate = 10, .hw_value = 0, .hw_value_short = 0, },
|
|
|
|
- { .bitrate = 20, .hw_value = 1, .hw_value_short = 1, },
|
|
|
|
- { .bitrate = 55, .hw_value = 2, .hw_value_short = 2, },
|
|
|
|
- { .bitrate = 110, .hw_value = 3, .hw_value_short = 3, },
|
|
|
|
- { .bitrate = 60, .hw_value = 4, .hw_value_short = 4, },
|
|
|
|
- { .bitrate = 90, .hw_value = 5, .hw_value_short = 5, },
|
|
|
|
- { .bitrate = 120, .hw_value = 6, .hw_value_short = 6, },
|
|
|
|
- { .bitrate = 180, .hw_value = 7, .hw_value_short = 7, },
|
|
|
|
- { .bitrate = 240, .hw_value = 8, .hw_value_short = 8, },
|
|
|
|
- { .bitrate = 360, .hw_value = 9, .hw_value_short = 9, },
|
|
|
|
- { .bitrate = 480, .hw_value = 10, .hw_value_short = 10, },
|
|
|
|
- { .bitrate = 540, .hw_value = 11, .hw_value_short = 11, },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/* can't be const, mac80211 writes to this */
|
|
|
|
-static struct ieee80211_channel stlc45xx_channels[] = {
|
|
|
|
- { .hw_value = 1, .center_freq = 2412},
|
|
|
|
- { .hw_value = 2, .center_freq = 2417},
|
|
|
|
- { .hw_value = 3, .center_freq = 2422},
|
|
|
|
- { .hw_value = 4, .center_freq = 2427},
|
|
|
|
- { .hw_value = 5, .center_freq = 2432},
|
|
|
|
- { .hw_value = 6, .center_freq = 2437},
|
|
|
|
- { .hw_value = 7, .center_freq = 2442},
|
|
|
|
- { .hw_value = 8, .center_freq = 2447},
|
|
|
|
- { .hw_value = 9, .center_freq = 2452},
|
|
|
|
- { .hw_value = 10, .center_freq = 2457},
|
|
|
|
- { .hw_value = 11, .center_freq = 2462},
|
|
|
|
- { .hw_value = 12, .center_freq = 2467},
|
|
|
|
- { .hw_value = 13, .center_freq = 2472},
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/* can't be const, mac80211 writes to this */
|
|
|
|
-static struct ieee80211_supported_band stlc45xx_band_2ghz = {
|
|
|
|
- .channels = stlc45xx_channels,
|
|
|
|
- .n_channels = ARRAY_SIZE(stlc45xx_channels),
|
|
|
|
- .bitrates = stlc45xx_rates,
|
|
|
|
- .n_bitrates = ARRAY_SIZE(stlc45xx_rates),
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static const struct ieee80211_ops stlc45xx_ops = {
|
|
|
|
- .start = stlc45xx_op_start,
|
|
|
|
- .stop = stlc45xx_op_stop,
|
|
|
|
- .add_interface = stlc45xx_op_add_interface,
|
|
|
|
- .remove_interface = stlc45xx_op_remove_interface,
|
|
|
|
- .config = stlc45xx_op_config,
|
|
|
|
- .configure_filter = stlc45xx_op_configure_filter,
|
|
|
|
- .tx = stlc45xx_op_tx,
|
|
|
|
- .bss_info_changed = stlc45xx_op_bss_info_changed,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int stlc45xx_register_mac80211(struct stlc45xx *stlc)
|
|
|
|
-{
|
|
|
|
- /* FIXME: SET_IEEE80211_PERM_ADDR() requires default_mac_addr
|
|
|
|
- to be non-const for some strange reason */
|
|
|
|
- static u8 default_mac_addr[ETH_ALEN] = {
|
|
|
|
- 0x00, 0x02, 0xee, 0xc0, 0xff, 0xee
|
|
|
|
- };
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- SET_IEEE80211_PERM_ADDR(stlc->hw, default_mac_addr);
|
|
|
|
-
|
|
|
|
- ret = ieee80211_register_hw(stlc->hw);
|
|
|
|
- if (ret) {
|
|
|
|
- stlc45xx_error("unable to register mac80211 hw: %d", ret);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void stlc45xx_device_release(struct device *dev)
|
|
|
|
-{
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static struct platform_device stlc45xx_device = {
|
|
|
|
- .name = "stlc45xx",
|
|
|
|
- .id = -1,
|
|
|
|
-
|
|
|
|
- /* device model insists to have a release function */
|
|
|
|
- .dev = {
|
|
|
|
- .release = stlc45xx_device_release,
|
|
|
|
- },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int __devinit stlc45xx_probe(struct spi_device *spi)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc;
|
|
|
|
- struct ieee80211_hw *hw;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- /* mac80211 alloc */
|
|
|
|
- hw = ieee80211_alloc_hw(sizeof(*stlc), &stlc45xx_ops);
|
|
|
|
- if (!hw) {
|
|
|
|
- stlc45xx_error("could not alloc ieee80211_hw");
|
|
|
|
- ret = -ENOMEM;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* mac80211 clears hw->priv */
|
|
|
|
- stlc = hw->priv;
|
|
|
|
-
|
|
|
|
- stlc->hw = hw;
|
|
|
|
- dev_set_drvdata(&spi->dev, stlc);
|
|
|
|
- stlc->spi = spi;
|
|
|
|
-
|
|
|
|
- spi->bits_per_word = 16;
|
|
|
|
- spi->max_speed_hz = 24000000;
|
|
|
|
-
|
|
|
|
- ret = spi_setup(spi);
|
|
|
|
- if (ret < 0)
|
|
|
|
- stlc45xx_error("spi_setup failed");
|
|
|
|
-
|
|
|
|
- ret = gpio_request(stlc45xx_gpio_power, "stlc45xx power");
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("power GPIO request failed: %d", ret);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = gpio_request(stlc45xx_gpio_irq, "stlc45xx irq");
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("irq GPIO request failed: %d", ret);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- gpio_direction_output(stlc45xx_gpio_power, 0);
|
|
|
|
- gpio_direction_input(stlc45xx_gpio_irq);
|
|
|
|
-
|
|
|
|
- ret = request_irq(gpio_to_irq(stlc45xx_gpio_irq),
|
|
|
|
- stlc45xx_interrupt, IRQF_DISABLED, "stlc45xx",
|
|
|
|
- stlc->spi);
|
|
|
|
- if (ret < 0)
|
|
|
|
- /* FIXME: handle the error */
|
|
|
|
- stlc45xx_error("request_irq() failed");
|
|
|
|
-
|
|
|
|
- set_irq_type(gpio_to_irq(stlc45xx_gpio_irq),
|
|
|
|
- IRQ_TYPE_EDGE_RISING);
|
|
|
|
-
|
|
|
|
- disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
|
|
|
|
-
|
|
|
|
- ret = platform_device_register(&stlc45xx_device);
|
|
|
|
- if (ret) {
|
|
|
|
- stlc45xx_error("Couldn't register wlan_omap device.");
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- dev_set_drvdata(&stlc45xx_device.dev, stlc);
|
|
|
|
-
|
|
|
|
- INIT_WORK(&stlc->work, stlc45xx_work);
|
|
|
|
- INIT_WORK(&stlc->work_reset, stlc45xx_work_reset);
|
|
|
|
- INIT_DELAYED_WORK(&stlc->work_tx_timeout, stlc45xx_work_tx_timeout);
|
|
|
|
- mutex_init(&stlc->mutex);
|
|
|
|
- init_completion(&stlc->fw_comp);
|
|
|
|
- spin_lock_init(&stlc->tx_lock);
|
|
|
|
- INIT_LIST_HEAD(&stlc->txbuffer);
|
|
|
|
- INIT_LIST_HEAD(&stlc->tx_pending);
|
|
|
|
- INIT_LIST_HEAD(&stlc->tx_sent);
|
|
|
|
-
|
|
|
|
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
|
|
|
- IEEE80211_HW_SIGNAL_DBM |
|
|
|
|
- IEEE80211_HW_NOISE_DBM;
|
|
|
|
- /* four bytes for padding */
|
|
|
|
- hw->extra_tx_headroom = sizeof(struct s_lm_data_out) + 4;
|
|
|
|
-
|
|
|
|
- /* unit us */
|
|
|
|
- hw->channel_change_time = 1000;
|
|
|
|
-
|
|
|
|
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
|
|
|
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &stlc45xx_band_2ghz;
|
|
|
|
-
|
|
|
|
- SET_IEEE80211_DEV(hw, &spi->dev);
|
|
|
|
-
|
|
|
|
- BUILD_BUG_ON(sizeof(default_cal_rssi) != RSSI_CAL_ARRAY_LEN);
|
|
|
|
- BUILD_BUG_ON(sizeof(default_cal_channels) != CHANNEL_CAL_ARRAY_LEN);
|
|
|
|
-
|
|
|
|
- stlc->cal_rssi = kmemdup(default_cal_rssi, RSSI_CAL_ARRAY_LEN,
|
|
|
|
- GFP_KERNEL);
|
|
|
|
- stlc->cal_channels = kmemdup(default_cal_channels,
|
|
|
|
- CHANNEL_CAL_ARRAY_LEN,
|
|
|
|
- GFP_KERNEL);
|
|
|
|
-
|
|
|
|
- ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_rssi);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("failed to create sysfs file cal_rssi");
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_channels);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("failed to create sysfs file cal_channels");
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = device_create_file(&stlc45xx_device.dev, &dev_attr_tx_buf);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("failed to create sysfs file tx_buf");
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = stlc45xx_register_mac80211(stlc);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- stlc45xx_info("v" DRIVER_VERSION " loaded");
|
|
|
|
-
|
|
|
|
- stlc45xx_info("config buffer 0x%x-0x%x",
|
|
|
|
- FIRMWARE_CONFIG_START, FIRMWARE_CONFIG_END);
|
|
|
|
- stlc45xx_info("tx 0x%x-0x%x, rx 0x%x-0x%x",
|
|
|
|
- FIRMWARE_TXBUFFER_START, FIRMWARE_TXBUFFER_END,
|
|
|
|
- FIRMWARE_RXBUFFER_START, FIRMWARE_RXBUFFER_END);
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int __devexit stlc45xx_remove(struct spi_device *spi)
|
|
|
|
-{
|
|
|
|
- struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- platform_device_unregister(&stlc45xx_device);
|
|
|
|
-
|
|
|
|
- ieee80211_unregister_hw(stlc->hw);
|
|
|
|
-
|
|
|
|
- free_irq(gpio_to_irq(stlc45xx_gpio_irq), spi);
|
|
|
|
-
|
|
|
|
- gpio_free(stlc45xx_gpio_power);
|
|
|
|
- gpio_free(stlc45xx_gpio_irq);
|
|
|
|
-
|
|
|
|
- /* FIXME: free cal_channels and cal_rssi? */
|
|
|
|
-
|
|
|
|
- kfree(stlc->fw);
|
|
|
|
-
|
|
|
|
- mutex_destroy(&stlc->mutex);
|
|
|
|
-
|
|
|
|
- /* frees also stlc */
|
|
|
|
- ieee80211_free_hw(stlc->hw);
|
|
|
|
- stlc = NULL;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static struct spi_driver stlc45xx_spi_driver = {
|
|
|
|
- .driver = {
|
|
|
|
- /* use cx3110x name because board-n800.c uses that for the
|
|
|
|
- * SPI port */
|
|
|
|
- .name = "cx3110x",
|
|
|
|
- .bus = &spi_bus_type,
|
|
|
|
- .owner = THIS_MODULE,
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- .probe = stlc45xx_probe,
|
|
|
|
- .remove = __devexit_p(stlc45xx_remove),
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int __init stlc45xx_init(void)
|
|
|
|
-{
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- ret = spi_register_driver(&stlc45xx_spi_driver);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- stlc45xx_error("failed to register SPI driver: %d", ret);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-out:
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void __exit stlc45xx_exit(void)
|
|
|
|
-{
|
|
|
|
- stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
|
|
|
|
-
|
|
|
|
- spi_unregister_driver(&stlc45xx_spi_driver);
|
|
|
|
-
|
|
|
|
- stlc45xx_info("unloaded");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-module_init(stlc45xx_init);
|
|
|
|
-module_exit(stlc45xx_exit);
|
|
|
|
-
|
|
|
|
-MODULE_LICENSE("GPL");
|
|
|
|
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
|
|
|
|
-MODULE_ALIAS("spi:cx3110x");
|
|
|