Staging patches for 3.19-rc1

Here's the big staging tree pull request for 3.19-rc1.
 
 We continued to delete more lines than were added, always a good thing,
 but not at a huge rate this release, only about 70k lines removed
 overall mostly from removing the horrid bcm driver.
 
 Lots of normal staging driver cleanups and fixes all over the place,
 well over a thousand of them, the shortlog shows all the horrid details.
 
 The "contentious" thing here is the movement of the Android binder code
 out of staging into the "real" part of the kernel.  This is code that
 has been stable for a few years now and is working as-is in the tens of
 millions of devices with no issues.  Yes, the code is horrid, and the
 userspace api leaves a lot to be desired, but it's not going to change
 due to legacy issues that we have no control over.  Because so many
 devices and companies rely on this, and the code is stable, might as
 well promote it out of staging.
 
 This was all discussed at the Linux Plumbers conference, and everyone
 participating agreed that this was the best way forward.
 
 There is work happening to replace the binder code with something new
 that is happening right now, but I don't expect to see the results of
 that work for another year at the earliest.  If that ever happens, and
 Android switches over to it, I'll gladly remove this version.
 
 As for maintainers, I'll be glad to maintain this code, I've been doing
 it for the past few years with no problems.  I'll send a MAINTAINERS
 entry for it before 3.19-final is out, still need to talk to the Google
 developers about if they are willing to help with it or not, last I
 checked they were, which was good.
 
 All of these patches have been in linux-next for a while with no
 reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlSPICkACgkQMUfUDdst+yksdwCfSLE9VUy1o2sAPDRe+J3bQced
 EWEAoL3RtnejKbo5tHS2IT69pLrwiIDS
 =YXyM
 -----END PGP SIGNATURE-----

Merge tag 'staging-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging driver updates from Greg KH:
 "Here's the big staging tree pull request for 3.19-rc1.

  We continued to delete more lines than were added, always a good
  thing, but not at a huge rate this release, only about 70k lines
  removed overall mostly from removing the horrid bcm driver.

  Lots of normal staging driver cleanups and fixes all over the place,
  well over a thousand of them, the shortlog shows all the horrid
  details.

  The "contentious" thing here is the movement of the Android binder
  code out of staging into the "real" part of the kernel.  This is code
  that has been stable for a few years now and is working as-is in the
  tens of millions of devices with no issues.  Yes, the code is horrid,
  and the userspace api leaves a lot to be desired, but it's not going
  to change due to legacy issues that we have no control over.  Because
  so many devices and companies rely on this, and the code is stable,
  might as well promote it out of staging.

  This was all discussed at the Linux Plumbers conference, and everyone
  participating agreed that this was the best way forward.

  There is work happening to replace the binder code with something new
  that is happening right now, but I don't expect to see the results of
  that work for another year at the earliest.  If that ever happens, and
  Android switches over to it, I'll gladly remove this version.

  As for maintainers, I'll be glad to maintain this code, I've been
  doing it for the past few years with no problems.  I'll send a
  MAINTAINERS entry for it before 3.19-final is out, still need to talk
  to the Google developers about if they are willing to help with it or
  not, last I checked they were, which was good.

  All of these patches have been in linux-next for a while with no
  reported issues"

* tag 'staging-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1382 commits)
  Staging: slicoss: Fix long line issues in slicoss.c
  staging: rtl8712: remove unnecessary else after return
  staging: comedi: change some printk calls to pr_err
  staging: rtl8723au: hal: Removed the extra semicolon
  lustre: Deletion of unnecessary checks before three function calls
  staging: lustre: fix sparse warnings: static function declaration
  staging: lustre: fixed sparse warnings related to static declarations
  staging: unisys: remove duplicate header
  staging: unisys: remove unneeded structure
  staging: ft1000 : replace __attribute ((__packed__) with __packed
  drivers: staging: rtl8192e: Include "asm/unaligned.h" instead of "access_ok.h" in "rtl819x_BAProc.c"
  Drivers:staging:rtl8192e: Fixed checkpatch warning
  Drivers:staging:clocking-wizard: Added a newline
  staging: clocking-wizard: check for a valid clk_name pointer
  staging: rtl8723au: Hal_InitPGData() avoid unnecessary typecasts
  staging: rtl8723au: _DisableAnalog(): Avoid zero-init variables unnecessarily
  staging: rtl8723au: Remove unnecessary wrapper _ResetDigitalProcedure1()
  staging: rtl8723au: _ResetDigitalProcedure1_92C() reduce code obfuscation
  staging: rtl8723au: Remove unnecessary wrapper _DisableRFAFEAndResetBB()
  staging: rtl8723au: _DisableRFAFEAndResetBB8192C(): Reduce code obfuscation
  ...
This commit is contained in:
Linus Torvalds 2014-12-15 18:06:13 -08:00
commit dab363f938
748 changed files with 21025 additions and 83015 deletions

View File

@ -200,6 +200,13 @@ Description:
Raw pressure measurement from channel Y. Units after
application of scale and offset are kilopascal.
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_input
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_input
KernelVersion: 3.8
Contact: linux-iio@vger.kernel.org
Description:
Scaled pressure measurement from channel Y, in kilopascal.
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_raw
KernelVersion: 3.14
Contact: linux-iio@vger.kernel.org
@ -231,6 +238,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@ -251,6 +259,7 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
@ -266,6 +275,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_sca
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@ -328,6 +338,10 @@ Description:
are listed in this attribute.
What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@ -1028,3 +1042,12 @@ Contact: linux-iio@vger.kernel.org
Description:
Raw value of rotation from true/magnetic north measured with
or without compensation from tilt sensors.
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw
KernelVersion: 3.18
Contact: linux-iio@vger.kernel.org
Description:
Raw current measurement from channel X. Units are in milliamps
after application of scale and offset. If no offset or scale is
present, output should be considered as processed with the
unit in milliamps.

View File

@ -16,6 +16,8 @@ Required properties:
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
Must be "samsung,exynos7-adc" for
the ADC in Exynos7 and compatibles
Must be "samsung,s3c2410-adc" for
the ADC in s3c2410 and compatibles
Must be "samsung,s3c2416-adc" for
@ -43,13 +45,16 @@ Required properties:
compatible ADC block)
- vdd-supply VDD input supply.
- samsung,syscon-phandle Contains the PMU system controller node
(To access the ADC_PHY register on Exynos5250/5420/5800/3250)
Note: child nodes can be added for auto probing from device tree.
Example: adding device info in dtsi file
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x12D10000 0x100>, <0x10040718 0x4>;
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
#io-channel-cells = <1>;
io-channel-ranges;
@ -58,13 +63,14 @@ adc: adc@12D10000 {
clock-names = "adc";
vdd-supply = <&buck5_reg>;
samsung,syscon-phandle = <&pmu_system_controller>;
};
Example: adding device info in dtsi file for Exynos3250 with additional sclk
adc: adc@126C0000 {
compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
reg = <0x126C0000 0x100>;
interrupts = <0 137 0>;
#io-channel-cells = <1>;
io-channel-ranges;
@ -73,6 +79,7 @@ adc: adc@126C0000 {
clock-names = "adc", "sclk";
vdd-supply = <&buck5_reg>;
samsung,syscon-phandle = <&pmu_system_controller>;
};
Example: Adding child nodes in dts file

View File

@ -0,0 +1,46 @@
Qualcomm's SPMI PMIC current ADC
QPNP PMIC current ADC (IADC) provides interface to clients to read current.
A 16 bit ADC is used for current measurements. IADC can measure the current
through an external resistor (channel 1) or internal (built-in) resistor
(channel 0). When using an external resistor it is to be described by
qcom,external-resistor-micro-ohms property.
IADC node:
- compatible:
Usage: required
Value type: <string>
Definition: Should contain "qcom,spmi-iadc".
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: IADC base address and length in the SPMI PMIC register map
- interrupts:
Usage: optional
Value type: <prop-encoded-array>
Definition: End of ADC conversion.
- qcom,external-resistor-micro-ohms:
Usage: optional
Value type: <u32>
Definition: Sense resister value in micro Ohm.
If not defined value of 10000 micro Ohms will be used.
Example:
/* IADC node */
pmic_iadc: iadc@3600 {
compatible = "qcom,spmi-iadc";
reg = <0x3600 0x100>;
interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
qcom,external-resistor-micro-ohms = <10000>;
#io-channel-cells = <1>;
};
/* IIO client node */
bat {
io-channels = <&pmic_iadc 0>;
io-channel-names = "iadc";
};

View File

@ -1,7 +1,7 @@
Rockchip Successive Approximation Register (SAR) A/D Converter bindings
Required properties:
- compatible: Should be "rockchip,saradc"
- compatible: Should be "rockchip,saradc" or "rockchip,rk3066-tsadc"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu. The interrupt specifier format

View File

@ -1925,13 +1925,6 @@ W: http://bcache.evilpiepirate.org
S: Maintained:
F: drivers/md/bcache/
BECEEM BCS200/BCS220-3/BCSM250 WIMAX SUPPORT
M: Kevin McKinney <klmckinney1@gmail.com>
M: Matthias Beyer <mail@beyermatthias.de>
L: devel@driverdev.osuosl.org
S: Maintained
F: drivers/staging/bcm*
BEFS FILE SYSTEM
S: Orphan
F: Documentation/filesystems/befs.txt

View File

@ -311,12 +311,13 @@
adc: adc@126C0000 {
compatible = "samsung,exynos3250-adc",
"samsung,exynos-adc-v2";
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
reg = <0x126C0000 0x100>;
interrupts = <0 137 0>;
clock-names = "adc", "sclk";
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
#io-channel-cells = <1>;
io-channel-ranges;
samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled";
};

View File

@ -108,13 +108,14 @@
adc: adc@126C0000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
reg = <0x126C0000 0x100>;
interrupt-parent = <&combiner>;
interrupts = <10 3>;
clocks = <&clock CLK_TSADC>;
clock-names = "adc";
#io-channel-cells = <1>;
io-channel-ranges;
samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled";
};

View File

@ -754,12 +754,13 @@
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x12D10000 0x100>, <0x10040718 0x4>;
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
clocks = <&clock CLK_ADC>;
clock-names = "adc";
#io-channel-cells = <1>;
io-channel-ranges;
samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled";
};

View File

@ -541,12 +541,13 @@
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>, <0x10040720 0x4>;
reg = <0x12D10000 0x100>;
interrupts = <0 106 0>;
clocks = <&clock CLK_TSADC>;
clock-names = "adc";
#io-channel-cells = <1>;
io-channel-ranges;
samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled";
};

View File

@ -184,4 +184,6 @@ source "drivers/ras/Kconfig"
source "drivers/thunderbolt/Kconfig"
source "drivers/android/Kconfig"
endmenu

View File

@ -162,3 +162,4 @@ obj-$(CONFIG_MCB) += mcb/
obj-$(CONFIG_RAS) += ras/
obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
obj-$(CONFIG_CORESIGHT) += coresight/
obj-$(CONFIG_ANDROID) += android/

37
drivers/android/Kconfig Normal file
View File

@ -0,0 +1,37 @@
menu "Android"
config ANDROID
bool "Android Drivers"
---help---
Enable support for various drivers needed on the Android platform
if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
depends on MMU
default n
---help---
Binder is used in Android for both communication between processes,
and remote method invocation.
This means one Android process can call a method/routine in another
Android process, using Binder to identify, invoke and pass arguments
between said processes.
config ANDROID_BINDER_IPC_32BIT
bool
depends on !64BIT && ANDROID_BINDER_IPC
default y
---help---
The Binder API has been changed to support both 32 and 64bit
applications in a mixed environment.
Enable this to support an old 32-bit Android user-space (v4.4 and
earlier).
Note that enabling this will break newer Android user-space.
endif # if ANDROID
endmenu

3
drivers/android/Makefile Normal file
View File

@ -0,0 +1,3 @@
ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o

View File

@ -38,7 +38,11 @@
#include <linux/slab.h>
#include <linux/pid_namespace.h>
#include "binder.h"
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
#define BINDER_IPC_32BIT 1
#endif
#include <uapi/linux/android/binder.h>
#include "binder_trace.h"
static DEFINE_MUTEX(binder_main_lock);

View File

@ -6,6 +6,7 @@ config DRM_IMX
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
depends on IMX_IPUV3_CORE
help
enable i.MX graphics support
@ -40,11 +41,11 @@ config DRM_IMX_LDB
found on i.MX53 and i.MX6 processors.
config DRM_IMX_IPUV3
tristate "DRM Support for i.MX IPUv3"
tristate
depends on DRM_IMX
depends on IMX_IPUV3_CORE
help
Choose this if you have a i.MX5 or i.MX6 processor.
default y if DRM_IMX=y
default m if DRM_IMX=m
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"

View File

@ -30,8 +30,6 @@
#define MAX_CRTC 4
struct imx_drm_crtc;
struct imx_drm_component {
struct device_node *of_node;
struct list_head list;
@ -633,7 +631,8 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
continue;
}
component_match_add(&pdev->dev, &match, compare_of, remote);
component_match_add(&pdev->dev, &match, compare_of,
remote);
of_node_put(remote);
}
of_node_put(port);

View File

@ -11,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/module.h>

View File

@ -11,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/clk.h>
@ -665,7 +660,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
if (ret < 0) {
dev_err(dev, "failed to read configuration register: %d\n", ret);
dev_err(dev, "failed to read configuration register: %d\n",
ret);
return ret;
}
if (val != 0x00100000) {

View File

@ -11,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/component.h>
#include <linux/module.h>

View File

@ -64,6 +64,7 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
{
struct drm_gem_cma_object *cma_obj;
unsigned long eba;
int active;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
if (!cma_obj) {
@ -74,12 +75,17 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
&cma_obj->paddr, x, y);
ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
eba = cma_obj->paddr + fb->offsets[0] +
fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
if (ipu_plane->enabled) {
active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
} else {
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
}
/* cache offsets for subsequent pageflips */
ipu_plane->x = x;
@ -137,6 +143,18 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
if (crtc_h < 2)
return -EINVAL;
/*
* since we cannot touch active IDMAC channels, we do not support
* resizing the enabled plane or changing its format
*/
if (ipu_plane->enabled) {
if (src_w != ipu_plane->w || src_h != ipu_plane->h ||
fb->pixel_format != ipu_plane->base.fb->pixel_format)
return -EINVAL;
return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
}
switch (ipu_plane->dp_flow) {
case IPU_DP_FLOW_SYNC_BG:
ret = ipu_dp_setup_channel(ipu_plane->dp,
@ -148,14 +166,22 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
ret);
return ret;
}
ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1);
ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
break;
case IPU_DP_FLOW_SYNC_FG:
ipu_dp_setup_channel(ipu_plane->dp,
ipu_drm_fourcc_to_colorspace(fb->pixel_format),
IPUV3_COLORSPACE_UNKNOWN);
ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
break;
/* Enable local alpha on partial plane */
switch (fb->pixel_format) {
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
break;
default:
break;
}
}
ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
@ -181,11 +207,16 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
return ret;
}
ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
if (ret < 0)
return ret;
ipu_plane->w = src_w;
ipu_plane->h = src_h;
return 0;
}

View File

@ -26,6 +26,8 @@ struct ipu_plane {
int x;
int y;
int w;
int h;
bool enabled;
};

View File

@ -11,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/component.h>
@ -128,6 +123,10 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
static void imx_pd_encoder_commit(struct drm_encoder *encoder)
{
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
drm_panel_prepare(imxpd->panel);
drm_panel_enable(imxpd->panel);
}
static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
@ -138,6 +137,10 @@ static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
static void imx_pd_encoder_disable(struct drm_encoder *encoder)
{
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
drm_panel_disable(imxpd->panel);
drm_panel_unprepare(imxpd->panel);
}
static struct drm_connector_funcs imx_pd_connector_funcs = {

View File

@ -33,8 +33,7 @@ static const struct st_sensors_platform_data default_accel_pdata = {
.drdy_int_pin = 1,
};
int st_accel_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata);
int st_accel_common_probe(struct iio_dev *indio_dev);
void st_accel_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER

View File

@ -161,7 +161,7 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensors st_accel_sensors[] = {
static const struct st_sensor_settings st_accel_sensors_settings[] = {
{
.wai = ST_ACCEL_1_WAI_EXP,
.sensors_supported = {
@ -457,8 +457,7 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#define ST_ACCEL_TRIGGER_OPS NULL
#endif
int st_accel_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *plat_data)
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
int irq = adata->get_irq_data_ready(indio_dev);
@ -470,24 +469,25 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
st_sensors_power_enable(indio_dev);
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
ARRAY_SIZE(st_accel_sensors_settings),
st_accel_sensors_settings);
if (err < 0)
return err;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor->multi_read_bit;
indio_dev->channels = adata->sensor->ch;
adata->multiread_bit = adata->sensor_settings->multi_read_bit;
indio_dev->channels = adata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
adata->current_fullscale = (struct st_sensor_fullscale_avl *)
&adata->sensor->fs.fs_avl[0];
adata->odr = adata->sensor->odr.odr_avl[0].hz;
&adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
if (!plat_data)
plat_data =
if (!adata->dev->platform_data)
adata->dev->platform_data =
(struct st_sensors_platform_data *)&default_accel_pdata;
err = st_sensors_init_sensor(indio_dev, plat_data);
err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
if (err < 0)
return err;

View File

@ -79,12 +79,11 @@ static int st_accel_i2c_probe(struct i2c_client *client,
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &client->dev;
st_sensors_of_i2c_probe(client, st_accel_of_match);
st_sensors_i2c_configure(indio_dev, client, adata);
err = st_accel_common_probe(indio_dev, client->dev.platform_data);
err = st_accel_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -29,11 +29,10 @@ static int st_accel_spi_probe(struct spi_device *spi)
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, adata);
err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
err = st_accel_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -214,6 +214,20 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
config QCOM_SPMI_IADC
tristate "Qualcomm SPMI PMIC current ADC"
depends on SPMI
select REGMAP_SPMI
help
This is the IIO Current ADC driver for Qualcomm QPNP IADC Chip.
The driver supports single mode operation to read from one of two
channels (external or internal). Hardware have additional
channels internally used for gain and offset calibration.
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-iadc.
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)

View File

@ -23,6 +23,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o

View File

@ -39,6 +39,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
@ -90,11 +92,14 @@
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
#define EXYNOS_ADCV1_PHY_OFFSET 0x0718
#define EXYNOS_ADCV2_PHY_OFFSET 0x0720
struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
void __iomem *regs;
void __iomem *enable_reg;
struct regmap *pmu_map;
struct clk *clk;
struct clk *sclk;
unsigned int irq;
@ -110,6 +115,7 @@ struct exynos_adc_data {
int num_channels;
bool needs_sclk;
bool needs_adc_phy;
int phy_offset;
u32 mask;
void (*init_hw)(struct exynos_adc *info);
@ -183,7 +189,7 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
u32 con1;
if (info->data->needs_adc_phy)
writel(1, info->enable_reg);
regmap_write(info->pmu_map, info->data->phy_offset, 1);
/* set default prescaler values and Enable prescaler */
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
@ -198,7 +204,7 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
u32 con;
if (info->data->needs_adc_phy)
writel(0, info->enable_reg);
regmap_write(info->pmu_map, info->data->phy_offset, 0);
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
@ -225,6 +231,7 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_adc_phy = true,
.phy_offset = EXYNOS_ADCV1_PHY_OFFSET,
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
@ -314,7 +321,7 @@ static void exynos_adc_v2_init_hw(struct exynos_adc *info)
u32 con1, con2;
if (info->data->needs_adc_phy)
writel(1, info->enable_reg);
regmap_write(info->pmu_map, info->data->phy_offset, 1);
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
@ -332,7 +339,7 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
u32 con;
if (info->data->needs_adc_phy)
writel(0, info->enable_reg);
regmap_write(info->pmu_map, info->data->phy_offset, 0);
con = readl(ADC_V2_CON1(info->regs));
con &= ~ADC_CON_EN_START;
@ -362,6 +369,7 @@ static const struct exynos_adc_data exynos_adc_v2_data = {
.num_channels = MAX_ADC_V2_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_adc_phy = true,
.phy_offset = EXYNOS_ADCV2_PHY_OFFSET,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
@ -374,6 +382,7 @@ static const struct exynos_adc_data exynos3250_adc_data = {
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_sclk = true,
.needs_adc_phy = true,
.phy_offset = EXYNOS_ADCV1_PHY_OFFSET,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
@ -381,6 +390,35 @@ static const struct exynos_adc_data exynos3250_adc_data = {
.start_conv = exynos_adc_v2_start_conv,
};
static void exynos_adc_exynos7_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
if (info->data->needs_adc_phy)
regmap_write(info->pmu_map, info->data->phy_offset, 1);
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_C_TIME(7);
con2 |= ADC_V2_CON2_C_TIME(0);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
}
static const struct exynos_adc_data exynos7_adc_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_exynos7_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
};
static const struct of_device_id exynos_adc_match[] = {
{
.compatible = "samsung,s3c2410-adc",
@ -406,6 +444,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,exynos3250-adc",
.data = &exynos3250_adc_data,
}, {
.compatible = "samsung,exynos7-adc",
.data = &exynos7_adc_data,
},
{},
};
@ -558,10 +599,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (info->data->needs_adc_phy) {
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->enable_reg))
return PTR_ERR(info->enable_reg);
info->pmu_map = syscon_regmap_lookup_by_phandle(
pdev->dev.of_node,
"samsung,syscon-phandle");
if (IS_ERR(info->pmu_map)) {
dev_err(&pdev->dev, "syscon regmap lookup failed.\n");
return PTR_ERR(info->pmu_map);
}
}
irq = platform_get_irq(pdev, 0);

View File

@ -1,9 +1,30 @@
/*
* Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
* Copyright (C) 2014 Rose Technology
* Allan Bendorff Jensen <abj@rosetechnology.dk>
* Soren Andersen <san@rosetechnology.dk>
*
* Driver for following ADC chips from Microchip Technology's:
* 10 Bit converter
* MCP3001
* MCP3002
* MCP3004
* MCP3008
* ------------
* 12 bit converter
* MCP3201
* MCP3202
* MCP3204
* MCP3208
* ------------
*
* Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
* Datasheet can be found here:
* http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
* http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf mcp3001
* http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf mcp3002
* http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf mcp3004/08
* http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201
* http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
*
* 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
@ -11,19 +32,29 @@
*/
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#define MCP_SINGLE_ENDED (1 << 3)
#define MCP_START_BIT (1 << 4)
enum {
mcp3001,
mcp3002,
mcp3004,
mcp3008,
mcp3201,
mcp3202,
mcp3204,
mcp3208,
};
struct mcp320x_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int resolution;
};
struct mcp320x {
struct spi_device *spi;
struct spi_message msg;
@ -34,19 +65,69 @@ struct mcp320x {
struct regulator *reg;
struct mutex lock;
const struct mcp320x_chip_info *chip_info;
};
static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
static int mcp320x_channel_to_tx_data(int device_index,
const unsigned int channel, bool differential)
{
int start_bit = 1;
switch (device_index) {
case mcp3001:
case mcp3201:
return 0;
case mcp3002:
case mcp3202:
return ((start_bit << 4) | (!differential << 3) |
(channel << 2));
case mcp3004:
case mcp3204:
case mcp3008:
case mcp3208:
return ((start_bit << 6) | (!differential << 5) |
(channel << 2));
default:
return -EINVAL;
}
}
static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
bool differential, int device_index)
{
int ret;
adc->tx_buf = msg;
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
adc->rx_buf[0] = 0;
adc->rx_buf[1] = 0;
adc->tx_buf = mcp320x_channel_to_tx_data(device_index,
channel, differential);
return ((adc->rx_buf[0] & 0x3f) << 6) |
(adc->rx_buf[1] >> 2);
if (device_index != mcp3001 && device_index != mcp3201) {
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
} else {
ret = spi_read(adc->spi, &adc->rx_buf, sizeof(adc->rx_buf));
if (ret < 0)
return ret;
}
switch (device_index) {
case mcp3001:
return (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3);
case mcp3002:
case mcp3004:
case mcp3008:
return (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6);
case mcp3201:
return (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1);
case mcp3202:
case mcp3204:
case mcp3208:
return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
default:
return -EINVAL;
}
}
static int mcp320x_read_raw(struct iio_dev *indio_dev,
@ -55,18 +136,17 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev,
{
struct mcp320x *adc = iio_priv(indio_dev);
int ret = -EINVAL;
int device_index = 0;
mutex_lock(&adc->lock);
device_index = spi_get_device_id(adc->spi)->driver_data;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (channel->differential)
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | channel->address);
else
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | MCP_SINGLE_ENDED |
channel->address);
ret = mcp320x_adc_conversion(adc, channel->address,
channel->differential, device_index);
if (ret < 0)
goto out;
@ -75,18 +155,15 @@ static int mcp320x_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_SCALE:
/* Digital output code = (4096 * Vin) / Vref */
ret = regulator_get_voltage(adc->reg);
if (ret < 0)
goto out;
/* convert regulator output voltage to mV */
*val = ret / 1000;
*val2 = 12;
*val2 = adc->chip_info->resolution;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
break;
}
out:
@ -117,6 +194,16 @@ out:
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec mcp3201_channels[] = {
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
};
static const struct iio_chan_spec mcp3202_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
};
static const struct iio_chan_spec mcp3204_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
@ -146,19 +233,46 @@ static const struct iio_info mcp320x_info = {
.driver_module = THIS_MODULE,
};
struct mcp3208_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
[mcp3001] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 10
},
[mcp3002] = {
.channels = mcp3202_channels,
.num_channels = ARRAY_SIZE(mcp3202_channels),
.resolution = 10
},
[mcp3004] = {
.channels = mcp3204_channels,
.num_channels = ARRAY_SIZE(mcp3204_channels),
.resolution = 10
},
[mcp3008] = {
.channels = mcp3208_channels,
.num_channels = ARRAY_SIZE(mcp3208_channels),
.resolution = 10
},
[mcp3201] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 12
},
[mcp3202] = {
.channels = mcp3202_channels,
.num_channels = ARRAY_SIZE(mcp3202_channels),
.resolution = 12
},
[mcp3204] = {
.channels = mcp3204_channels,
.num_channels = ARRAY_SIZE(mcp3204_channels)
.num_channels = ARRAY_SIZE(mcp3204_channels),
.resolution = 12
},
[mcp3208] = {
.channels = mcp3208_channels,
.num_channels = ARRAY_SIZE(mcp3208_channels)
.num_channels = ARRAY_SIZE(mcp3208_channels),
.resolution = 12
},
};
@ -166,7 +280,7 @@ static int mcp320x_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mcp320x *adc;
const struct mcp3208_chip_info *chip_info;
const struct mcp320x_chip_info *chip_info;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
@ -181,7 +295,7 @@ static int mcp320x_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp320x_info;
chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data];
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
@ -226,7 +340,45 @@ static int mcp320x_remove(struct spi_device *spi)
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id mcp320x_dt_ids[] = {
{
.compatible = "mcp3001",
.data = &mcp320x_chip_infos[mcp3001],
}, {
.compatible = "mcp3002",
.data = &mcp320x_chip_infos[mcp3002],
}, {
.compatible = "mcp3004",
.data = &mcp320x_chip_infos[mcp3004],
}, {
.compatible = "mcp3008",
.data = &mcp320x_chip_infos[mcp3008],
}, {
.compatible = "mcp3201",
.data = &mcp320x_chip_infos[mcp3201],
}, {
.compatible = "mcp3202",
.data = &mcp320x_chip_infos[mcp3202],
}, {
.compatible = "mcp3204",
.data = &mcp320x_chip_infos[mcp3204],
}, {
.compatible = "mcp3208",
.data = &mcp320x_chip_infos[mcp3208],
}, {
}
};
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
#endif
static const struct spi_device_id mcp320x_id[] = {
{ "mcp3001", mcp3001 },
{ "mcp3002", mcp3002 },
{ "mcp3004", mcp3004 },
{ "mcp3008", mcp3008 },
{ "mcp3201", mcp3201 },
{ "mcp3202", mcp3202 },
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ }
@ -245,5 +397,5 @@ static struct spi_driver mcp320x_driver = {
module_spi_driver(mcp320x_driver);
MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,595 @@
/*
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
/* IADC register and bit definition */
#define IADC_REVISION2 0x1
#define IADC_REVISION2_SUPPORTED_IADC 1
#define IADC_PERPH_TYPE 0x4
#define IADC_PERPH_TYPE_ADC 8
#define IADC_PERPH_SUBTYPE 0x5
#define IADC_PERPH_SUBTYPE_IADC 3
#define IADC_STATUS1 0x8
#define IADC_STATUS1_OP_MODE 4
#define IADC_STATUS1_REQ_STS BIT(1)
#define IADC_STATUS1_EOC BIT(0)
#define IADC_STATUS1_REQ_STS_EOC_MASK 0x3
#define IADC_MODE_CTL 0x40
#define IADC_OP_MODE_SHIFT 3
#define IADC_OP_MODE_NORMAL 0
#define IADC_TRIM_EN BIT(0)
#define IADC_EN_CTL1 0x46
#define IADC_EN_CTL1_SET BIT(7)
#define IADC_CH_SEL_CTL 0x48
#define IADC_DIG_PARAM 0x50
#define IADC_DIG_DEC_RATIO_SEL_SHIFT 2
#define IADC_HW_SETTLE_DELAY 0x51
#define IADC_CONV_REQ 0x52
#define IADC_CONV_REQ_SET BIT(7)
#define IADC_FAST_AVG_CTL 0x5a
#define IADC_FAST_AVG_EN 0x5b
#define IADC_FAST_AVG_EN_SET BIT(7)
#define IADC_PERH_RESET_CTL3 0xda
#define IADC_FOLLOW_WARM_RB BIT(2)
#define IADC_DATA 0x60 /* 16 bits */
#define IADC_SEC_ACCESS 0xd0
#define IADC_SEC_ACCESS_DATA 0xa5
#define IADC_NOMINAL_RSENSE 0xf4
#define IADC_NOMINAL_RSENSE_SIGN_MASK BIT(7)
#define IADC_REF_GAIN_MICRO_VOLTS 17857
#define IADC_INT_RSENSE_DEVIATION 15625 /* nano Ohms per bit */
#define IADC_INT_RSENSE_IDEAL_VALUE 10000 /* micro Ohms */
#define IADC_INT_RSENSE_DEFAULT_VALUE 7800 /* micro Ohms */
#define IADC_INT_RSENSE_DEFAULT_GF 9000 /* micro Ohms */
#define IADC_INT_RSENSE_DEFAULT_SMIC 9700 /* micro Ohms */
#define IADC_CONV_TIME_MIN_US 2000
#define IADC_CONV_TIME_MAX_US 2100
#define IADC_DEF_PRESCALING 0 /* 1:1 */
#define IADC_DEF_DECIMATION 0 /* 512 */
#define IADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
#define IADC_DEF_AVG_SAMPLES 0 /* 1 sample */
/* IADC channel list */
#define IADC_INT_RSENSE 0
#define IADC_EXT_RSENSE 1
#define IADC_GAIN_17P857MV 3
#define IADC_EXT_OFFSET_CSP_CSN 5
#define IADC_INT_OFFSET_CSP2_CSN2 6
/**
* struct iadc_chip - IADC Current ADC device structure.
* @regmap: regmap for register read/write.
* @dev: This device pointer.
* @base: base offset for the ADC peripheral.
* @rsense: Values of the internal and external sense resister in micro Ohms.
* @poll_eoc: Poll for end of conversion instead of waiting for IRQ.
* @offset: Raw offset values for the internal and external channels.
* @gain: Raw gain of the channels.
* @lock: ADC lock for access to the peripheral.
* @complete: ADC notification after end of conversion interrupt is received.
*/
struct iadc_chip {
struct regmap *regmap;
struct device *dev;
u16 base;
bool poll_eoc;
u32 rsense[2];
u16 offset[2];
u16 gain;
struct mutex lock;
struct completion complete;
};
static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
{
unsigned int val;
int ret;
ret = regmap_read(iadc->regmap, iadc->base + offset, &val);
if (ret < 0)
return ret;
*data = val;
return 0;
}
static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data)
{
return regmap_write(iadc->regmap, iadc->base + offset, data);
}
static int iadc_reset(struct iadc_chip *iadc)
{
u8 data;
int ret;
ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
if (ret < 0)
return ret;
ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data);
if (ret < 0)
return ret;
ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
if (ret < 0)
return ret;
data |= IADC_FOLLOW_WARM_RB;
return iadc_write(iadc, IADC_PERH_RESET_CTL3, data);
}
static int iadc_set_state(struct iadc_chip *iadc, bool state)
{
return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0);
}
static void iadc_status_show(struct iadc_chip *iadc)
{
u8 mode, sta1, chan, dig, en, req;
int ret;
ret = iadc_read(iadc, IADC_MODE_CTL, &mode);
if (ret < 0)
return;
ret = iadc_read(iadc, IADC_DIG_PARAM, &dig);
if (ret < 0)
return;
ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan);
if (ret < 0)
return;
ret = iadc_read(iadc, IADC_CONV_REQ, &req);
if (ret < 0)
return;
ret = iadc_read(iadc, IADC_STATUS1, &sta1);
if (ret < 0)
return;
ret = iadc_read(iadc, IADC_EN_CTL1, &en);
if (ret < 0)
return;
dev_err(iadc->dev,
"mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
mode, en, chan, dig, req, sta1);
}
static int iadc_configure(struct iadc_chip *iadc, int channel)
{
u8 decim, mode;
int ret;
/* Mode selection */
mode = (IADC_OP_MODE_NORMAL << IADC_OP_MODE_SHIFT) | IADC_TRIM_EN;
ret = iadc_write(iadc, IADC_MODE_CTL, mode);
if (ret < 0)
return ret;
/* Channel selection */
ret = iadc_write(iadc, IADC_CH_SEL_CTL, channel);
if (ret < 0)
return ret;
/* Digital parameter setup */
decim = IADC_DEF_DECIMATION << IADC_DIG_DEC_RATIO_SEL_SHIFT;
ret = iadc_write(iadc, IADC_DIG_PARAM, decim);
if (ret < 0)
return ret;
/* HW settle time delay */
ret = iadc_write(iadc, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME);
if (ret < 0)
return ret;
ret = iadc_write(iadc, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES);
if (ret < 0)
return ret;
if (IADC_DEF_AVG_SAMPLES)
ret = iadc_write(iadc, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET);
else
ret = iadc_write(iadc, IADC_FAST_AVG_EN, 0);
if (ret < 0)
return ret;
if (!iadc->poll_eoc)
reinit_completion(&iadc->complete);
ret = iadc_set_state(iadc, true);
if (ret < 0)
return ret;
/* Request conversion */
return iadc_write(iadc, IADC_CONV_REQ, IADC_CONV_REQ_SET);
}
static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
{
unsigned int count, retry;
int ret;
u8 sta1;
retry = interval_us / IADC_CONV_TIME_MIN_US;
for (count = 0; count < retry; count++) {
ret = iadc_read(iadc, IADC_STATUS1, &sta1);
if (ret < 0)
return ret;
sta1 &= IADC_STATUS1_REQ_STS_EOC_MASK;
if (sta1 == IADC_STATUS1_EOC)
return 0;
usleep_range(IADC_CONV_TIME_MIN_US, IADC_CONV_TIME_MAX_US);
}
iadc_status_show(iadc);
return -ETIMEDOUT;
}
static int iadc_read_result(struct iadc_chip *iadc, u16 *data)
{
return regmap_bulk_read(iadc->regmap, iadc->base + IADC_DATA, data, 2);
}
static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
{
unsigned int wait;
int ret;
ret = iadc_configure(iadc, chan);
if (ret < 0)
goto exit;
wait = BIT(IADC_DEF_AVG_SAMPLES) * IADC_CONV_TIME_MIN_US * 2;
if (iadc->poll_eoc) {
ret = iadc_poll_wait_eoc(iadc, wait);
} else {
ret = wait_for_completion_timeout(&iadc->complete, wait);
if (!ret)
ret = -ETIMEDOUT;
else
/* double check conversion status */
ret = iadc_poll_wait_eoc(iadc, IADC_CONV_TIME_MIN_US);
}
if (!ret)
ret = iadc_read_result(iadc, data);
exit:
iadc_set_state(iadc, false);
if (ret < 0)
dev_err(iadc->dev, "conversion failed\n");
return ret;
}
static int iadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct iadc_chip *iadc = iio_priv(indio_dev);
s32 isense_ua, vsense_uv;
u16 adc_raw, vsense_raw;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&iadc->lock);
ret = iadc_do_conversion(iadc, chan->channel, &adc_raw);
mutex_unlock(&iadc->lock);
if (ret < 0)
return ret;
vsense_raw = adc_raw - iadc->offset[chan->channel];
vsense_uv = vsense_raw * IADC_REF_GAIN_MICRO_VOLTS;
vsense_uv /= (s32)iadc->gain - iadc->offset[chan->channel];
isense_ua = vsense_uv / iadc->rsense[chan->channel];
dev_dbg(iadc->dev, "off %d gain %d adc %d %duV I %duA\n",
iadc->offset[chan->channel], iadc->gain,
adc_raw, vsense_uv, isense_ua);
*val = isense_ua;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static const struct iio_info iadc_info = {
.read_raw = iadc_read_raw,
.driver_module = THIS_MODULE,
};
static irqreturn_t iadc_isr(int irq, void *dev_id)
{
struct iadc_chip *iadc = dev_id;
complete(&iadc->complete);
return IRQ_HANDLED;
}
static int iadc_update_offset(struct iadc_chip *iadc)
{
int ret;
ret = iadc_do_conversion(iadc, IADC_GAIN_17P857MV, &iadc->gain);
if (ret < 0)
return ret;
ret = iadc_do_conversion(iadc, IADC_INT_OFFSET_CSP2_CSN2,
&iadc->offset[IADC_INT_RSENSE]);
if (ret < 0)
return ret;
if (iadc->gain == iadc->offset[IADC_INT_RSENSE]) {
dev_err(iadc->dev, "error: internal offset == gain %d\n",
iadc->gain);
return -EINVAL;
}
ret = iadc_do_conversion(iadc, IADC_EXT_OFFSET_CSP_CSN,
&iadc->offset[IADC_EXT_RSENSE]);
if (ret < 0)
return ret;
if (iadc->gain == iadc->offset[IADC_EXT_RSENSE]) {
dev_err(iadc->dev, "error: external offset == gain %d\n",
iadc->gain);
return -EINVAL;
}
return 0;
}
static int iadc_version_check(struct iadc_chip *iadc)
{
u8 val;
int ret;
ret = iadc_read(iadc, IADC_PERPH_TYPE, &val);
if (ret < 0)
return ret;
if (val < IADC_PERPH_TYPE_ADC) {
dev_err(iadc->dev, "%d is not ADC\n", val);
return -EINVAL;
}
ret = iadc_read(iadc, IADC_PERPH_SUBTYPE, &val);
if (ret < 0)
return ret;
if (val < IADC_PERPH_SUBTYPE_IADC) {
dev_err(iadc->dev, "%d is not IADC\n", val);
return -EINVAL;
}
ret = iadc_read(iadc, IADC_REVISION2, &val);
if (ret < 0)
return ret;
if (val < IADC_REVISION2_SUPPORTED_IADC) {
dev_err(iadc->dev, "revision %d not supported\n", val);
return -EINVAL;
}
return 0;
}
static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node)
{
int ret, sign, int_sense;
u8 deviation;
ret = of_property_read_u32(node, "qcom,external-resistor-micro-ohms",
&iadc->rsense[IADC_EXT_RSENSE]);
if (ret < 0)
iadc->rsense[IADC_EXT_RSENSE] = IADC_INT_RSENSE_IDEAL_VALUE;
if (!iadc->rsense[IADC_EXT_RSENSE]) {
dev_err(iadc->dev, "external resistor can't be zero Ohms");
return -EINVAL;
}
ret = iadc_read(iadc, IADC_NOMINAL_RSENSE, &deviation);
if (ret < 0)
return ret;
/*
* Deviation value stored is an offset from 10 mili Ohms, bit 7 is
* the sign, the remaining bits have an LSB of 15625 nano Ohms.
*/
sign = (deviation & IADC_NOMINAL_RSENSE_SIGN_MASK) ? -1 : 1;
deviation &= ~IADC_NOMINAL_RSENSE_SIGN_MASK;
/* Scale it to nono Ohms */
int_sense = IADC_INT_RSENSE_IDEAL_VALUE * 1000;
int_sense += sign * deviation * IADC_INT_RSENSE_DEVIATION;
int_sense /= 1000; /* micro Ohms */
iadc->rsense[IADC_INT_RSENSE] = int_sense;
return 0;
}
static const struct iio_chan_spec iadc_channels[] = {
{
.type = IIO_CURRENT,
.datasheet_name = "INTERNAL_RSENSE",
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
},
{
.type = IIO_CURRENT,
.datasheet_name = "EXTERNAL_RSENSE",
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
},
};
static int iadc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct iadc_chip *iadc;
int ret, irq_eoc;
u32 res;
indio_dev = devm_iio_device_alloc(dev, sizeof(*iadc));
if (!indio_dev)
return -ENOMEM;
iadc = iio_priv(indio_dev);
iadc->dev = dev;
iadc->regmap = dev_get_regmap(dev->parent, NULL);
if (!iadc->regmap)
return -ENODEV;
init_completion(&iadc->complete);
mutex_init(&iadc->lock);
ret = of_property_read_u32(node, "reg", &res);
if (ret < 0)
return -ENODEV;
iadc->base = res;
ret = iadc_version_check(iadc);
if (ret < 0)
return -ENODEV;
ret = iadc_rsense_read(iadc, node);
if (ret < 0)
return -ENODEV;
dev_dbg(iadc->dev, "sense resistors %d and %d micro Ohm\n",
iadc->rsense[IADC_INT_RSENSE],
iadc->rsense[IADC_EXT_RSENSE]);
irq_eoc = platform_get_irq(pdev, 0);
if (irq_eoc == -EPROBE_DEFER)
return irq_eoc;
if (irq_eoc < 0)
iadc->poll_eoc = true;
ret = iadc_reset(iadc);
if (ret < 0) {
dev_err(dev, "reset failed\n");
return ret;
}
if (!iadc->poll_eoc) {
ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0,
"spmi-iadc", iadc);
if (!ret)
enable_irq_wake(irq_eoc);
else
return ret;
} else {
device_init_wakeup(iadc->dev, 1);
}
ret = iadc_update_offset(iadc);
if (ret < 0) {
dev_err(dev, "failed offset calibration\n");
return ret;
}
indio_dev->dev.parent = dev;
indio_dev->dev.of_node = node;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &iadc_info;
indio_dev->channels = iadc_channels;
indio_dev->num_channels = ARRAY_SIZE(iadc_channels);
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id iadc_match_table[] = {
{ .compatible = "qcom,spmi-iadc" },
{ }
};
MODULE_DEVICE_TABLE(of, iadc_match_table);
static struct platform_driver iadc_driver = {
.driver = {
.name = "qcom-spmi-iadc",
.of_match_table = iadc_match_table,
},
.probe = iadc_probe,
};
module_platform_driver(iadc_driver);
MODULE_ALIAS("platform:qcom-spmi-iadc");
MODULE_DESCRIPTION("Qualcomm SPMI PMIC current ADC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");

View File

@ -18,13 +18,13 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#define SARADC_DATA 0x00
#define SARADC_DATA_MASK 0x3ff
#define SARADC_STAS 0x04
#define SARADC_STAS_BUSY BIT(0)
@ -38,15 +38,22 @@
#define SARADC_DLY_PU_SOC 0x0c
#define SARADC_DLY_PU_SOC_MASK 0x3f
#define SARADC_BITS 10
#define SARADC_TIMEOUT msecs_to_jiffies(100)
struct rockchip_saradc_data {
int num_bits;
const struct iio_chan_spec *channels;
int num_channels;
unsigned long clk_rate;
};
struct rockchip_saradc {
void __iomem *regs;
struct clk *pclk;
struct clk *clk;
struct completion completion;
struct regulator *vref;
const struct rockchip_saradc_data *data;
u16 last_val;
};
@ -90,7 +97,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
}
*val = ret / 1000;
*val2 = SARADC_BITS;
*val2 = info->data->num_bits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
@ -103,7 +110,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
/* Read value */
info->last_val = readl_relaxed(info->regs + SARADC_DATA);
info->last_val &= SARADC_DATA_MASK;
info->last_val &= GENMASK(info->data->num_bits - 1, 0);
/* Clear irq & power down adc */
writel_relaxed(0, info->regs + SARADC_CTRL);
@ -133,12 +140,44 @@ static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
ADC_CHANNEL(2, "adc2"),
};
static const struct rockchip_saradc_data saradc_data = {
.num_bits = 10,
.channels = rockchip_saradc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
.clk_rate = 1000000,
};
static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
};
static const struct rockchip_saradc_data rk3066_tsadc_data = {
.num_bits = 12,
.channels = rockchip_rk3066_tsadc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
.clk_rate = 50000,
};
static const struct of_device_id rockchip_saradc_match[] = {
{
.compatible = "rockchip,saradc",
.data = &saradc_data,
}, {
.compatible = "rockchip,rk3066-tsadc",
.data = &rk3066_tsadc_data,
},
{},
};
MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
static int rockchip_saradc_probe(struct platform_device *pdev)
{
struct rockchip_saradc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
const struct of_device_id *match;
int ret;
int irq;
@ -152,6 +191,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
}
info = iio_priv(indio_dev);
match = of_match_device(rockchip_saradc_match, &pdev->dev);
info->data = match->data;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
@ -192,10 +234,10 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
}
/*
* Use a default of 1MHz for the converter clock.
* Use a default value for the converter clock.
* This may become user-configurable in the future.
*/
ret = clk_set_rate(info->clk, 1000000);
ret = clk_set_rate(info->clk, info->data->clk_rate);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
return ret;
@ -227,8 +269,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
indio_dev->info = &rockchip_saradc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = rockchip_saradc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels);
indio_dev->channels = info->data->channels;
indio_dev->num_channels = info->data->num_channels;
ret = iio_device_register(indio_dev);
if (ret)
@ -296,12 +338,6 @@ static int rockchip_saradc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
rockchip_saradc_suspend, rockchip_saradc_resume);
static const struct of_device_id rockchip_saradc_match[] = {
{ .compatible = "rockchip,saradc" },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
static struct platform_driver rockchip_saradc_driver = {
.probe = rockchip_saradc_probe,
.remove = rockchip_saradc_remove,

View File

@ -91,7 +91,7 @@
#define VF610_ADC_CAL 0x80
/* Other field define */
#define VF610_ADC_ADCHC(x) ((x) & 0xF)
#define VF610_ADC_ADCHC(x) ((x) & 0x1F)
#define VF610_ADC_AIEN (0x1 << 7)
#define VF610_ADC_CONV_DISABLE 0x1F
#define VF610_ADC_HS_COCO0 0x1
@ -153,6 +153,12 @@ struct vf610_adc {
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(0, IIO_VOLTAGE),
VF610_ADC_CHAN(1, IIO_VOLTAGE),
@ -170,6 +176,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(13, IIO_VOLTAGE),
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
/* sentinel */
};
@ -451,6 +458,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
@ -468,7 +476,23 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
return ret;
}
*val = info->value;
switch (chan->type) {
case IIO_VOLTAGE:
*val = info->value;
break;
case IIO_TEMP:
/*
* Calculate in degree Celsius times 1000
* Using sensor slope of 1.84 mV/°C and
* V at 25°C of 696 mV
*/
*val = 25000 - ((int)info->value - 864) * 1000000 / 1840;
break;
default:
mutex_unlock(&indio_dev->mlock);
return -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
@ -569,9 +593,9 @@ static int vf610_adc_probe(struct platform_device *pdev)
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return -EINVAL;
return irq;
}
ret = devm_request_irq(info->dev, irq,
@ -586,8 +610,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
ret = PTR_ERR(info->clk);
return ret;
return PTR_ERR(info->clk);
}
info->vref = devm_regulator_get(&pdev->dev, "vref");
@ -681,17 +704,19 @@ static int vf610_adc_resume(struct device *dev)
ret = clk_prepare_enable(info->clk);
if (ret)
return ret;
goto disable_reg;
vf610_adc_hw_init(info);
return 0;
disable_reg:
regulator_disable(info->vref);
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
vf610_adc_suspend,
vf610_adc_resume);
static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, vf610_adc_resume);
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,

View File

@ -44,18 +44,18 @@ st_sensors_write_data_with_mask_error:
return err;
}
static int st_sensors_match_odr(struct st_sensors *sensor,
static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
unsigned int odr, struct st_sensor_odr_avl *odr_out)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sensor->odr.odr_avl[i].hz == 0)
if (sensor_settings->odr.odr_avl[i].hz == 0)
goto st_sensors_match_odr_error;
if (sensor->odr.odr_avl[i].hz == odr) {
odr_out->hz = sensor->odr.odr_avl[i].hz;
odr_out->value = sensor->odr.odr_avl[i].value;
if (sensor_settings->odr.odr_avl[i].hz == odr) {
odr_out->hz = sensor_settings->odr.odr_avl[i].hz;
odr_out->value = sensor_settings->odr.odr_avl[i].value;
ret = 0;
break;
}
@ -71,23 +71,26 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
struct st_sensor_odr_avl odr_out = {0, 0};
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
if (err < 0)
goto st_sensors_match_odr_error;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
if ((sdata->sensor_settings->odr.addr ==
sdata->sensor_settings->pw.addr) &&
(sdata->sensor_settings->odr.mask ==
sdata->sensor_settings->pw.mask)) {
if (sdata->enabled == true) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr,
sdata->sensor->odr.mask,
sdata->sensor_settings->odr.addr,
sdata->sensor_settings->odr.mask,
odr_out.value);
} else {
err = 0;
}
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr, sdata->sensor->odr.mask,
sdata->sensor_settings->odr.addr,
sdata->sensor_settings->odr.mask,
odr_out.value);
}
if (err >= 0)
@ -98,16 +101,16 @@ st_sensors_match_odr_error:
}
EXPORT_SYMBOL(st_sensors_set_odr);
static int st_sensors_match_fs(struct st_sensors *sensor,
static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
unsigned int fs, int *index_fs_avl)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sensor->fs.fs_avl[i].num == 0)
if (sensor_settings->fs.fs_avl[i].num == 0)
goto st_sensors_match_odr_error;
if (sensor->fs.fs_avl[i].num == fs) {
if (sensor_settings->fs.fs_avl[i].num == fs) {
*index_fs_avl = i;
ret = 0;
break;
@ -118,25 +121,24 @@ st_sensors_match_odr_error:
return ret;
}
static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
unsigned int fs)
static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
{
int err, i = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_fs(sdata->sensor, fs, &i);
err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
if (err < 0)
goto st_accel_set_fullscale_error;
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->fs.addr,
sdata->sensor->fs.mask,
sdata->sensor->fs.fs_avl[i].value);
sdata->sensor_settings->fs.addr,
sdata->sensor_settings->fs.mask,
sdata->sensor_settings->fs.fs_avl[i].value);
if (err < 0)
goto st_accel_set_fullscale_error;
sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&sdata->sensor->fs.fs_avl[i];
&sdata->sensor_settings->fs.fs_avl[i];
return err;
st_accel_set_fullscale_error:
@ -153,10 +155,12 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (enable) {
tmp_value = sdata->sensor->pw.value_on;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
err = st_sensors_match_odr(sdata->sensor,
tmp_value = sdata->sensor_settings->pw.value_on;
if ((sdata->sensor_settings->odr.addr ==
sdata->sensor_settings->pw.addr) &&
(sdata->sensor_settings->odr.mask ==
sdata->sensor_settings->pw.mask)) {
err = st_sensors_match_odr(sdata->sensor_settings,
sdata->odr, &odr_out);
if (err < 0)
goto set_enable_error;
@ -164,8 +168,8 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
found = true;
}
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask, tmp_value);
sdata->sensor_settings->pw.addr,
sdata->sensor_settings->pw.mask, tmp_value);
if (err < 0)
goto set_enable_error;
@ -175,9 +179,9 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
sdata->odr = odr_out.hz;
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask,
sdata->sensor->pw.value_off);
sdata->sensor_settings->pw.addr,
sdata->sensor_settings->pw.mask,
sdata->sensor_settings->pw.value_off);
if (err < 0)
goto set_enable_error;
@ -194,8 +198,9 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
struct st_sensor_data *sdata = iio_priv(indio_dev);
return st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->enable_axis.addr,
sdata->sensor->enable_axis.mask, axis_enable);
sdata->sensor_settings->enable_axis.addr,
sdata->sensor_settings->enable_axis.mask,
axis_enable);
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
@ -236,13 +241,13 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
EXPORT_SYMBOL(st_sensors_power_disable);
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
struct st_sensors_platform_data *pdata)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
switch (pdata->drdy_int_pin) {
case 1:
if (sdata->sensor->drdy_irq.mask_int1 == 0) {
if (sdata->sensor_settings->drdy_irq.mask_int1 == 0) {
dev_err(&indio_dev->dev,
"DRDY on INT1 not available.\n");
return -EINVAL;
@ -250,7 +255,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
sdata->drdy_int_pin = 1;
break;
case 2:
if (sdata->sensor->drdy_irq.mask_int2 == 0) {
if (sdata->sensor_settings->drdy_irq.mask_int2 == 0) {
dev_err(&indio_dev->dev,
"DRDY on INT2 not available.\n");
return -EINVAL;
@ -318,7 +323,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
if (sdata->current_fullscale) {
err = st_sensors_set_fullscale(indio_dev,
sdata->current_fullscale->num);
sdata->current_fullscale->num);
if (err < 0)
return err;
} else
@ -330,7 +335,8 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
/* set BDU */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
sdata->sensor_settings->bdu.addr,
sdata->sensor_settings->bdu.mask, true);
if (err < 0)
return err;
@ -346,26 +352,28 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
u8 drdy_mask;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor->drdy_irq.addr)
if (!sdata->sensor_settings->drdy_irq.addr)
return 0;
/* Enable/Disable the interrupt generator 1. */
if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.ig1.en_addr,
sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
sdata->sensor_settings->drdy_irq.ig1.en_addr,
sdata->sensor_settings->drdy_irq.ig1.en_mask,
(int)enable);
if (err < 0)
goto st_accel_set_dataready_irq_error;
}
if (sdata->drdy_int_pin == 1)
drdy_mask = sdata->sensor->drdy_irq.mask_int1;
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
else
drdy_mask = sdata->sensor->drdy_irq.mask_int2;
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
sdata->sensor_settings->drdy_irq.addr,
drdy_mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
@ -378,8 +386,8 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
(sdata->sensor->fs.fs_avl[i].gain != 0)) {
if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) &&
(sdata->sensor_settings->fs.fs_avl[i].gain != 0)) {
err = 0;
break;
}
@ -388,7 +396,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
goto st_sensors_match_scale_error;
err = st_sensors_set_fullscale(indio_dev,
sdata->sensor->fs.fs_avl[i].num);
sdata->sensor_settings->fs.fs_avl[i].num);
st_sensors_match_scale_error:
return err;
@ -439,7 +447,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
if (err < 0)
goto out;
msleep((sdata->sensor->bootime * 1000) / sdata->odr);
msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr);
err = st_sensors_read_axis_data(indio_dev, ch, val);
if (err < 0)
goto out;
@ -456,7 +464,8 @@ out:
EXPORT_SYMBOL(st_sensors_read_info_raw);
int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list, const struct st_sensors *sensors)
int num_sensors_list,
const struct st_sensor_settings *sensor_settings)
{
u8 wai;
int i, n, err;
@ -470,23 +479,24 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
}
for (i = 0; i < num_sensors_list; i++) {
if (sensors[i].wai == wai)
if (sensor_settings[i].wai == wai)
break;
}
if (i == num_sensors_list)
goto device_not_supported;
for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) {
if (strcmp(indio_dev->name,
&sensors[i].sensors_supported[n][0]) == 0)
&sensor_settings[i].sensors_supported[n][0]) == 0)
break;
}
if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) {
dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
goto sensor_name_mismatch;
}
sdata->sensor = (struct st_sensors *)&sensors[i];
sdata->sensor_settings =
(struct st_sensor_settings *)&sensor_settings[i];
return i;
@ -508,11 +518,11 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sdata->sensor->odr.odr_avl[i].hz == 0)
if (sdata->sensor_settings->odr.odr_avl[i].hz == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
sdata->sensor->odr.odr_avl[i].hz);
sdata->sensor_settings->odr.odr_avl[i].hz);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';
@ -530,11 +540,11 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sdata->sensor->fs.fs_avl[i].num == 0)
if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
sdata->sensor->fs.fs_avl[i].gain);
sdata->sensor_settings->fs.fs_avl[i].gain);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';

View File

@ -72,6 +72,7 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
indio_dev->dev.parent = &client->dev;
indio_dev->name = client->name;
sdata->dev = &client->dev;
sdata->tf = &st_sensors_tf_i2c;
sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
}

View File

@ -111,6 +111,7 @@ void st_sensors_spi_configure(struct iio_dev *indio_dev,
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi->modalias;
sdata->dev = &spi->dev;
sdata->tf = &st_sensors_tf_spi;
sdata->get_irq_data_ready = st_sensors_spi_get_irq;
}

View File

@ -30,8 +30,7 @@ static const struct st_sensors_platform_data gyro_pdata = {
.drdy_int_pin = 2,
};
int st_gyro_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata);
int st_gyro_common_probe(struct iio_dev *indio_dev);
void st_gyro_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER

View File

@ -103,7 +103,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensors st_gyro_sensors[] = {
static const struct st_sensor_settings st_gyro_sensors_settings[] = {
{
.wai = ST_GYRO_1_WAI_EXP,
.sensors_supported = {
@ -309,8 +309,7 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = {
#define ST_GYRO_TRIGGER_OPS NULL
#endif
int st_gyro_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
int st_gyro_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *gdata = iio_priv(indio_dev);
int irq = gdata->get_irq_data_ready(indio_dev);
@ -322,20 +321,22 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
st_sensors_power_enable(indio_dev);
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors);
ARRAY_SIZE(st_gyro_sensors_settings),
st_gyro_sensors_settings);
if (err < 0)
return err;
gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
gdata->multiread_bit = gdata->sensor->multi_read_bit;
indio_dev->channels = gdata->sensor->ch;
gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
indio_dev->channels = gdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
gdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&gdata->sensor->fs.fs_avl[0];
gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
&gdata->sensor_settings->fs.fs_avl[0];
gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz;
err = st_sensors_init_sensor(indio_dev, pdata);
err = st_sensors_init_sensor(indio_dev,
(struct st_sensors_platform_data *)&gyro_pdata);
if (err < 0)
return err;

View File

@ -67,13 +67,11 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
return -ENOMEM;
gdata = iio_priv(indio_dev);
gdata->dev = &client->dev;
st_sensors_of_i2c_probe(client, st_gyro_of_match);
st_sensors_i2c_configure(indio_dev, client, gdata);
err = st_gyro_common_probe(indio_dev,
(struct st_sensors_platform_data *)&gyro_pdata);
err = st_gyro_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -29,12 +29,10 @@ static int st_gyro_spi_probe(struct spi_device *spi)
return -ENOMEM;
gdata = iio_priv(indio_dev);
gdata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, gdata);
err = st_gyro_common_probe(indio_dev,
(struct st_sensors_platform_data *)&gyro_pdata);
err = st_gyro_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -22,4 +22,14 @@ config SI7005
To compile this driver as a module, choose M here: the module
will be called si7005.
config SI7020
tristate "Si7013/20/21 Relative Humidity and Temperature Sensors"
depends on I2C
help
Say yes here to build support for the Silicon Labs Si7013/20/21
Relative Humidity and Temperature Sensors.
To compile this driver as a module, choose M here: the module
will be called si7020.
endmenu

View File

@ -4,3 +4,4 @@
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o

View File

@ -0,0 +1,161 @@
/*
* si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
* Copyright (c) 2013,2014 Uplogix, Inc.
* David Barksdale <dbarksdale@uplogix.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions 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.
*/
/*
* The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
* are i2c devices which have an identical programming interface for
* measuring relative humidity and temperature. The Si7013 has an additional
* temperature input which this driver does not support.
*
* Data Sheets:
* Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
* Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
* Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* Measure Relative Humidity, Hold Master Mode */
#define SI7020CMD_RH_HOLD 0xE5
/* Measure Temperature, Hold Master Mode */
#define SI7020CMD_TEMP_HOLD 0xE3
/* Software Reset */
#define SI7020CMD_RESET 0xFE
static int si7020_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct i2c_client *client = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_data(client,
chan->type == IIO_TEMP ?
SI7020CMD_TEMP_HOLD :
SI7020CMD_RH_HOLD);
if (ret < 0)
return ret;
*val = ret >> 2;
if (chan->type == IIO_HUMIDITYRELATIVE)
*val &= GENMASK(11, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP)
*val = 175720; /* = 175.72 * 1000 */
else
*val = 125 * 1000;
*val2 = 65536 >> 2;
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_OFFSET:
/*
* Since iio_convert_raw_to_processed_unlocked assumes offset
* is an integer we have to round these values and lose
* accuracy.
* Relative humidity will be 0.0032959% too high and
* temperature will be 0.00277344 degrees too high.
* This is no big deal because it's within the accuracy of the
* sensor.
*/
if (chan->type == IIO_TEMP)
*val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
else
*val = -786; /* = -6 * (65536 >> 2) / 125 */
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static const struct iio_chan_spec si7020_channels[] = {
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
},
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
}
};
static const struct iio_info si7020_info = {
.read_raw = si7020_read_raw,
.driver_module = THIS_MODULE,
};
static int si7020_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct i2c_client **data;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_WORD_DATA))
return -ENODEV;
/* Reset device, loads default settings. */
ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
if (ret < 0)
return ret;
/* Wait the maximum power-up time after software reset. */
msleep(15);
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
*data = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &si7020_info;
indio_dev->channels = si7020_channels;
indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id si7020_id[] = {
{ "si7020", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7020_id);
static struct i2c_driver si7020_driver = {
.driver.name = "si7020",
.probe = si7020_probe,
.id_table = si7020_id,
};
module_i2c_driver(si7020_driver);
MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
MODULE_LICENSE("GPL");

View File

@ -100,6 +100,28 @@ static int iio_dev_node_match(struct device *dev, void *data)
return dev->of_node == data && dev->type == &iio_device_type;
}
/**
* __of_iio_simple_xlate - translate iiospec to the IIO channel index
* @indio_dev: pointer to the iio_dev structure
* @iiospec: IIO specifier as found in the device tree
*
* This is simple translation function, suitable for the most 1:1 mapped
* channels in IIO chips. This function performs only one sanity check:
* whether IIO index is less than num_channels (that is specified in the
* iio_dev).
*/
static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
const struct of_phandle_args *iiospec)
{
if (!iiospec->args_count)
return 0;
if (iiospec->args[0] >= indio_dev->num_channels)
return -EINVAL;
return iiospec->args[0];
}
static int __of_iio_channel_get(struct iio_channel *channel,
struct device_node *np, int index)
{
@ -122,18 +144,19 @@ static int __of_iio_channel_get(struct iio_channel *channel,
indio_dev = dev_to_iio_dev(idev);
channel->indio_dev = indio_dev;
index = iiospec.args_count ? iiospec.args[0] : 0;
if (index >= indio_dev->num_channels) {
err = -EINVAL;
if (indio_dev->info->of_xlate)
index = indio_dev->info->of_xlate(indio_dev, &iiospec);
else
index = __of_iio_simple_xlate(indio_dev, &iiospec);
if (index < 0)
goto err_put;
}
channel->channel = &indio_dev->channels[index];
return 0;
err_put:
iio_device_put(indio_dev);
return err;
return index;
}
static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)

View File

@ -18,8 +18,7 @@
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
int st_magn_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata);
int st_magn_common_probe(struct iio_dev *indio_dev);
void st_magn_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER

View File

@ -149,7 +149,7 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensors st_magn_sensors[] = {
static const struct st_sensor_settings st_magn_sensors_settings[] = {
{
.wai = ST_MAGN_1_WAI_EXP,
.sensors_supported = {
@ -361,8 +361,7 @@ static const struct iio_info magn_info = {
.write_raw = &st_magn_write_raw,
};
int st_magn_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
int st_magn_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
int irq = mdata->get_irq_data_ready(indio_dev);
@ -374,20 +373,21 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
st_sensors_power_enable(indio_dev);
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
ARRAY_SIZE(st_magn_sensors_settings),
st_magn_sensors_settings);
if (err < 0)
return err;
mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
mdata->multiread_bit = mdata->sensor->multi_read_bit;
indio_dev->channels = mdata->sensor->ch;
mdata->multiread_bit = mdata->sensor_settings->multi_read_bit;
indio_dev->channels = mdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
mdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&mdata->sensor->fs.fs_avl[0];
mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
&mdata->sensor_settings->fs.fs_avl[0];
mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz;
err = st_sensors_init_sensor(indio_dev, pdata);
err = st_sensors_init_sensor(indio_dev, NULL);
if (err < 0)
return err;

View File

@ -51,12 +51,11 @@ static int st_magn_i2c_probe(struct i2c_client *client,
return -ENOMEM;
mdata = iio_priv(indio_dev);
mdata->dev = &client->dev;
st_sensors_of_i2c_probe(client, st_magn_of_match);
st_sensors_i2c_configure(indio_dev, client, mdata);
err = st_magn_common_probe(indio_dev, NULL);
err = st_magn_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -29,11 +29,10 @@ static int st_magn_spi_probe(struct spi_device *spi)
return -ENOMEM;
mdata = iio_priv(indio_dev);
mdata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, mdata);
err = st_magn_common_probe(indio_dev, NULL);
err = st_magn_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -5,6 +5,17 @@
menu "Pressure sensors"
config BMP280
tristate "Bosch Sensortec BMP280 pressure sensor driver"
depends on I2C
select REGMAP_I2C
help
Say yes here to build support for Bosch Sensortec BMP280
pressure and temperature sensor.
To compile this driver as a module, choose M here: the module
will be called bmp280.
config HID_SENSOR_PRESS
depends on HID_SENSOR_HUB
select IIO_BUFFER

View File

@ -3,6 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMP280) += bmp280.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_MPL115) += mpl115.o
obj-$(CONFIG_MPL3115) += mpl3115.o

View File

@ -0,0 +1,455 @@
/*
* Copyright (c) 2014 Intel Corporation
*
* Driver for Bosch Sensortec BMP280 digital pressure sensor.
*
* 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.
*
*/
#define pr_fmt(fmt) "bmp280: " fmt
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define BMP280_REG_TEMP_XLSB 0xFC
#define BMP280_REG_TEMP_LSB 0xFB
#define BMP280_REG_TEMP_MSB 0xFA
#define BMP280_REG_PRESS_XLSB 0xF9
#define BMP280_REG_PRESS_LSB 0xF8
#define BMP280_REG_PRESS_MSB 0xF7
#define BMP280_REG_CONFIG 0xF5
#define BMP280_REG_CTRL_MEAS 0xF4
#define BMP280_REG_STATUS 0xF3
#define BMP280_REG_RESET 0xE0
#define BMP280_REG_ID 0xD0
#define BMP280_REG_COMP_TEMP_START 0x88
#define BMP280_COMP_TEMP_REG_COUNT 6
#define BMP280_REG_COMP_PRESS_START 0x8E
#define BMP280_COMP_PRESS_REG_COUNT 18
#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2))
#define BMP280_FILTER_OFF 0
#define BMP280_FILTER_2X BIT(2)
#define BMP280_FILTER_4X BIT(3)
#define BMP280_FILTER_8X (BIT(3) | BIT(2))
#define BMP280_FILTER_16X BIT(4)
#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5))
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X BIT(5)
#define BMP280_OSRS_TEMP_2X BIT(6)
#define BMP280_OSRS_TEMP_4X (BIT(6) | BIT(5))
#define BMP280_OSRS_TEMP_8X BIT(7)
#define BMP280_OSRS_TEMP_16X (BIT(7) | BIT(5))
#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2))
#define BMP280_OSRS_PRESS_SKIP 0
#define BMP280_OSRS_PRESS_1X BIT(2)
#define BMP280_OSRS_PRESS_2X BIT(3)
#define BMP280_OSRS_PRESS_4X (BIT(3) | BIT(2))
#define BMP280_OSRS_PRESS_8X BIT(4)
#define BMP280_OSRS_PRESS_16X (BIT(4) | BIT(2))
#define BMP280_MODE_MASK (BIT(1) | BIT(0))
#define BMP280_MODE_SLEEP 0
#define BMP280_MODE_FORCED BIT(0)
#define BMP280_MODE_NORMAL (BIT(1) | BIT(0))
#define BMP280_CHIP_ID 0x58
#define BMP280_SOFT_RESET_VAL 0xB6
struct bmp280_data {
struct i2c_client *client;
struct mutex lock;
struct regmap *regmap;
/*
* Carryover value from temperature conversion, used in pressure
* calculation.
*/
s32 t_fine;
};
/* Compensation parameters. */
struct bmp280_comp_temp {
u16 dig_t1;
s16 dig_t2, dig_t3;
};
struct bmp280_comp_press {
u16 dig_p1;
s16 dig_p2, dig_p3, dig_p4, dig_p5, dig_p6, dig_p7, dig_p8, dig_p9;
};
static const struct iio_chan_spec bmp280_channels[] = {
{
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMP280_REG_CONFIG:
case BMP280_REG_CTRL_MEAS:
case BMP280_REG_RESET:
return true;
default:
return false;
};
}
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMP280_REG_TEMP_XLSB:
case BMP280_REG_TEMP_LSB:
case BMP280_REG_TEMP_MSB:
case BMP280_REG_PRESS_XLSB:
case BMP280_REG_PRESS_LSB:
case BMP280_REG_PRESS_MSB:
case BMP280_REG_STATUS:
return true;
default:
return false;
}
}
static const struct regmap_config bmp280_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMP280_REG_TEMP_XLSB,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bmp280_is_writeable_reg,
.volatile_reg = bmp280_is_volatile_reg,
};
static int bmp280_read_compensation_temp(struct bmp280_data *data,
struct bmp280_comp_temp *comp)
{
int ret;
__le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
buf, BMP280_COMP_TEMP_REG_COUNT);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to read temperature calibration parameters\n");
return ret;
}
comp->dig_t1 = (u16) le16_to_cpu(buf[0]);
comp->dig_t2 = (s16) le16_to_cpu(buf[1]);
comp->dig_t3 = (s16) le16_to_cpu(buf[2]);
return 0;
}
static int bmp280_read_compensation_press(struct bmp280_data *data,
struct bmp280_comp_press *comp)
{
int ret;
__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
buf, BMP280_COMP_PRESS_REG_COUNT);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to read pressure calibration parameters\n");
return ret;
}
comp->dig_p1 = (u16) le16_to_cpu(buf[0]);
comp->dig_p2 = (s16) le16_to_cpu(buf[1]);
comp->dig_p3 = (s16) le16_to_cpu(buf[2]);
comp->dig_p4 = (s16) le16_to_cpu(buf[3]);
comp->dig_p5 = (s16) le16_to_cpu(buf[4]);
comp->dig_p6 = (s16) le16_to_cpu(buf[5]);
comp->dig_p7 = (s16) le16_to_cpu(buf[6]);
comp->dig_p8 = (s16) le16_to_cpu(buf[7]);
comp->dig_p9 = (s16) le16_to_cpu(buf[8]);
return 0;
}
/*
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
* "5123" equals 51.23 DegC. t_fine carries fine temperature as global
* value.
*
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static s32 bmp280_compensate_temp(struct bmp280_data *data,
struct bmp280_comp_temp *comp,
s32 adc_temp)
{
s32 var1, var2, t;
var1 = (((adc_temp >> 3) - ((s32) comp->dig_t1 << 1)) *
((s32) comp->dig_t2)) >> 11;
var2 = (((((adc_temp >> 4) - ((s32) comp->dig_t1)) *
((adc_temp >> 4) - ((s32) comp->dig_t1))) >> 12) *
((s32) comp->dig_t3)) >> 14;
data->t_fine = var1 + var2;
t = (data->t_fine * 5 + 128) >> 8;
return t;
}
/*
* Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24
* integer bits and 8 fractional bits). Output value of "24674867"
* represents 24674867/256 = 96386.2 Pa = 963.862 hPa
*
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static u32 bmp280_compensate_press(struct bmp280_data *data,
struct bmp280_comp_press *comp,
s32 adc_press)
{
s64 var1, var2, p;
var1 = ((s64) data->t_fine) - 128000;
var2 = var1 * var1 * (s64) comp->dig_p6;
var2 = var2 + ((var1 * (s64) comp->dig_p5) << 17);
var2 = var2 + (((s64) comp->dig_p4) << 35);
var1 = ((var1 * var1 * (s64) comp->dig_p3) >> 8) +
((var1 * (s64) comp->dig_p2) << 12);
var1 = (((((s64) 1) << 47) + var1)) * ((s64) comp->dig_p1) >> 33;
if (var1 == 0)
return 0;
p = ((((s64) 1048576 - adc_press) << 31) - var2) * 3125;
p = div64_s64(p, var1);
var1 = (((s64) comp->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((s64) comp->dig_p8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((s64) comp->dig_p7) << 4);
return (u32) p;
}
static int bmp280_read_temp(struct bmp280_data *data,
int *val)
{
int ret;
__be32 tmp = 0;
s32 adc_temp, comp_temp;
struct bmp280_comp_temp comp;
ret = bmp280_read_compensation_temp(data, &comp);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
(u8 *) &tmp, 3);
if (ret < 0) {
dev_err(&data->client->dev, "failed to read temperature\n");
return ret;
}
adc_temp = be32_to_cpu(tmp) >> 12;
comp_temp = bmp280_compensate_temp(data, &comp, adc_temp);
/*
* val might be NULL if we're called by the read_press routine,
* who only cares about the carry over t_fine value.
*/
if (val) {
*val = comp_temp * 10;
return IIO_VAL_INT;
}
return 0;
}
static int bmp280_read_press(struct bmp280_data *data,
int *val, int *val2)
{
int ret;
__be32 tmp = 0;
s32 adc_press;
u32 comp_press;
struct bmp280_comp_press comp;
ret = bmp280_read_compensation_press(data, &comp);
if (ret < 0)
return ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp280_read_temp(data, NULL);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
(u8 *) &tmp, 3);
if (ret < 0) {
dev_err(&data->client->dev, "failed to read pressure\n");
return ret;
}
adc_press = be32_to_cpu(tmp) >> 12;
comp_press = bmp280_compensate_press(data, &comp, adc_press);
*val = comp_press;
*val2 = 256000;
return IIO_VAL_FRACTIONAL;
}
static int bmp280_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct bmp280_data *data = iio_priv(indio_dev);
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_PRESSURE:
ret = bmp280_read_press(data, val, val2);
break;
case IIO_TEMP:
ret = bmp280_read_temp(data, val);
break;
default:
ret = -EINVAL;
break;
}
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&data->lock);
return ret;
}
static const struct iio_info bmp280_info = {
.driver_module = THIS_MODULE,
.read_raw = &bmp280_read_raw,
};
static int bmp280_chip_init(struct bmp280_data *data)
{
int ret;
ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_MEAS,
BMP280_OSRS_TEMP_MASK |
BMP280_OSRS_PRESS_MASK |
BMP280_MODE_MASK,
BMP280_OSRS_TEMP_2X |
BMP280_OSRS_PRESS_16X |
BMP280_MODE_NORMAL);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to write config register\n");
return ret;
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
BMP280_FILTER_MASK,
BMP280_FILTER_4X);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to write config register\n");
return ret;
}
return ret;
}
static int bmp280_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct bmp280_data *data;
unsigned int chip_id;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
i2c_set_clientdata(client, indio_dev);
data = iio_priv(indio_dev);
mutex_init(&data->lock);
data->client = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->channels = bmp280_channels;
indio_dev->num_channels = ARRAY_SIZE(bmp280_channels);
indio_dev->info = &bmp280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
data->regmap = devm_regmap_init_i2c(client, &bmp280_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(&client->dev, "failed to allocate register map\n");
return PTR_ERR(data->regmap);
}
ret = regmap_read(data->regmap, BMP280_REG_ID, &chip_id);
if (ret < 0)
return ret;
if (chip_id != BMP280_CHIP_ID) {
dev_err(&client->dev, "bad chip id. expected %x got %x\n",
BMP280_CHIP_ID, chip_id);
return -EINVAL;
}
ret = bmp280_chip_init(data);
if (ret < 0)
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct acpi_device_id bmp280_acpi_match[] = {
{"BMP0280", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match);
static const struct i2c_device_id bmp280_id[] = {
{"bmp280", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, bmp280_id);
static struct i2c_driver bmp280_driver = {
.driver = {
.name = "bmp280",
.acpi_match_table = ACPI_PTR(bmp280_acpi_match),
},
.probe = bmp280_probe,
.id_table = bmp280_id,
};
module_i2c_driver(bmp280_driver);
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP280 pressure and temperature sensor");
MODULE_LICENSE("GPL v2");

View File

@ -26,8 +26,7 @@ static const struct st_sensors_platform_data default_press_pdata = {
.drdy_int_pin = 1,
};
int st_press_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata);
int st_press_common_probe(struct iio_dev *indio_dev);
void st_press_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER

View File

@ -38,10 +38,10 @@ static int st_press_buffer_preenable(struct iio_dev *indio_dev)
static int st_press_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *pdata = iio_priv(indio_dev);
struct st_sensor_data *press_data = iio_priv(indio_dev);
pdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (pdata->buffer_data == NULL) {
press_data->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (press_data->buffer_data == NULL) {
err = -ENOMEM;
goto allocate_memory_error;
}
@ -53,7 +53,7 @@ static int st_press_buffer_postenable(struct iio_dev *indio_dev)
return err;
st_press_buffer_postenable_error:
kfree(pdata->buffer_data);
kfree(press_data->buffer_data);
allocate_memory_error:
return err;
}
@ -61,7 +61,7 @@ allocate_memory_error:
static int st_press_buffer_predisable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *pdata = iio_priv(indio_dev);
struct st_sensor_data *press_data = iio_priv(indio_dev);
err = iio_triggered_buffer_predisable(indio_dev);
if (err < 0)
@ -70,7 +70,7 @@ static int st_press_buffer_predisable(struct iio_dev *indio_dev)
err = st_sensors_set_enable(indio_dev, false);
st_press_buffer_predisable_error:
kfree(pdata->buffer_data);
kfree(press_data->buffer_data);
return err;
}

View File

@ -175,7 +175,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1)
};
static const struct st_sensors st_press_sensors[] = {
static const struct st_sensor_settings st_press_sensors_settings[] = {
{
.wai = ST_PRESS_LPS331AP_WAI_EXP,
.sensors_supported = {
@ -333,7 +333,7 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
int err;
struct st_sensor_data *pdata = iio_priv(indio_dev);
struct st_sensor_data *press_data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
@ -347,10 +347,10 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
switch (ch->type) {
case IIO_PRESSURE:
*val2 = pdata->current_fullscale->gain;
*val2 = press_data->current_fullscale->gain;
break;
case IIO_TEMP:
*val2 = pdata->current_fullscale->gain2;
*val2 = press_data->current_fullscale->gain2;
break;
default:
err = -EINVAL;
@ -371,7 +371,7 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = pdata->odr;
*val = press_data->odr;
return IIO_VAL_INT;
default:
return -EINVAL;
@ -409,11 +409,10 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
#define ST_PRESS_TRIGGER_OPS NULL
#endif
int st_press_common_probe(struct iio_dev *indio_dev,
struct st_sensors_platform_data *plat_data)
int st_press_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
int irq = pdata->get_irq_data_ready(indio_dev);
struct st_sensor_data *press_data = iio_priv(indio_dev);
int irq = press_data->get_irq_data_ready(indio_dev);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
@ -422,28 +421,30 @@ int st_press_common_probe(struct iio_dev *indio_dev,
st_sensors_power_enable(indio_dev);
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_press_sensors),
st_press_sensors);
ARRAY_SIZE(st_press_sensors_settings),
st_press_sensors_settings);
if (err < 0)
return err;
pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
pdata->multiread_bit = pdata->sensor->multi_read_bit;
indio_dev->channels = pdata->sensor->ch;
indio_dev->num_channels = pdata->sensor->num_ch;
press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
indio_dev->channels = press_data->sensor_settings->ch;
indio_dev->num_channels = press_data->sensor_settings->num_ch;
if (pdata->sensor->fs.addr != 0)
pdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&pdata->sensor->fs.fs_avl[0];
if (press_data->sensor_settings->fs.addr != 0)
press_data->current_fullscale =
(struct st_sensor_fullscale_avl *)
&press_data->sensor_settings->fs.fs_avl[0];
pdata->odr = pdata->sensor->odr.odr_avl[0].hz;
press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
/* Some devices don't support a data ready pin. */
if (!plat_data && pdata->sensor->drdy_irq.addr)
plat_data =
if (!press_data->dev->platform_data &&
press_data->sensor_settings->drdy_irq.addr)
press_data->dev->platform_data =
(struct st_sensors_platform_data *)&default_press_pdata;
err = st_sensors_init_sensor(indio_dev, plat_data);
err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
if (err < 0)
return err;
@ -479,12 +480,12 @@ EXPORT_SYMBOL(st_press_common_probe);
void st_press_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
struct st_sensor_data *press_data = iio_priv(indio_dev);
st_sensors_power_disable(indio_dev);
iio_device_unregister(indio_dev);
if (pdata->get_irq_data_ready(indio_dev) > 0)
if (press_data->get_irq_data_ready(indio_dev) > 0)
st_sensors_deallocate_trigger(indio_dev);
st_press_deallocate_ring(indio_dev);

View File

@ -43,20 +43,19 @@ static int st_press_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct st_sensor_data *pdata;
struct st_sensor_data *press_data;
int err;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pdata));
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data));
if (!indio_dev)
return -ENOMEM;
pdata = iio_priv(indio_dev);
pdata->dev = &client->dev;
press_data = iio_priv(indio_dev);
st_sensors_of_i2c_probe(client, st_press_of_match);
st_sensors_i2c_configure(indio_dev, client, pdata);
st_sensors_i2c_configure(indio_dev, client, press_data);
err = st_press_common_probe(indio_dev, client->dev.platform_data);
err = st_press_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -21,19 +21,18 @@
static int st_press_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct st_sensor_data *pdata;
struct st_sensor_data *press_data;
int err;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*pdata));
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*press_data));
if (indio_dev == NULL)
return -ENOMEM;
pdata = iio_priv(indio_dev);
pdata->dev = &spi->dev;
press_data = iio_priv(indio_dev);
st_sensors_spi_configure(indio_dev, spi, pdata);
st_sensors_spi_configure(indio_dev, spi, press_data);
err = st_press_common_probe(indio_dev, spi->dev.platform_data);
err = st_press_common_probe(indio_dev);
if (err < 0)
return err;

View File

@ -95,7 +95,7 @@ static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
*val = ret;
return 0;
};
}
static int as3935_write(struct as3935_state *st,
unsigned int reg,
@ -107,7 +107,7 @@ static int as3935_write(struct as3935_state *st,
buf[1] = val;
return spi_write(st->spi, buf, 2);
};
}
static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
struct device_attribute *attr,
@ -122,7 +122,7 @@ static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
val = (val & AS3935_AFE_MASK) >> 1;
return sprintf(buf, "%d\n", val);
};
}
static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
struct device_attribute *attr,
@ -142,7 +142,7 @@ static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
as3935_write(st, AS3935_AFE_GAIN, val << 1);
return len;
};
}
static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
@ -214,7 +214,7 @@ err_read:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
};
}
static const struct iio_trigger_ops iio_interrupt_trigger_ops = {
.owner = THIS_MODULE,
@ -238,7 +238,7 @@ static void as3935_event_work(struct work_struct *work)
dev_warn(&st->spi->dev, "noise level is too high");
break;
}
};
}
static irqreturn_t as3935_interrupt_handler(int irq, void *private)
{
@ -417,7 +417,7 @@ unregister_trigger:
iio_trigger_unregister(st->trig);
return ret;
};
}
static int as3935_remove(struct spi_device *spi)
{
@ -429,7 +429,7 @@ static int as3935_remove(struct spi_device *spi)
iio_trigger_unregister(st->trig);
return 0;
};
}
static const struct spi_device_id as3935_id[] = {
{"as3935", 0},

View File

@ -62,8 +62,6 @@ source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/emxx_udc/Kconfig"
source "drivers/staging/bcm/Kconfig"
source "drivers/staging/ft1000/Kconfig"
source "drivers/staging/speakup/Kconfig"
@ -106,4 +104,6 @@ source "drivers/staging/skein/Kconfig"
source "drivers/staging/unisys/Kconfig"
source "drivers/staging/clocking-wizard/Kconfig"
endif # STAGING

View File

@ -25,7 +25,6 @@ obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_BCM_WIMAX) += bcm/
obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
@ -45,3 +44,4 @@ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/
obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
obj-$(CONFIG_CRYPTO_SKEIN) += skein/
obj-$(CONFIG_UNISYSSPAR) += unisys/
obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/

View File

@ -1,37 +1,7 @@
menu "Android"
config ANDROID
bool "Android Drivers"
---help---
Enable support for various drivers needed on the Android platform
if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
depends on MMU
default n
---help---
Binder is used in Android for both communication between processes,
and remote method invocation.
This means one Android process can call a method/routine in another
Android process, using Binder to identify, invoke and pass arguments
between said processes.
config ANDROID_BINDER_IPC_32BIT
bool
depends on !64BIT && ANDROID_BINDER_IPC
default y
---help---
The Binder API has been changed to support both 32 and 64bit
applications in a mixed environment.
Enable this to support an old 32-bit Android user-space (v4.4 and
earlier).
Note that enabling this will break newer Android user-space.
config ASHMEM
bool "Enable the Anonymous Shared Memory Subsystem"
default n

View File

@ -2,7 +2,6 @@ ccflags-y += -I$(src) # needed for trace events
obj-y += ion/
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o

View File

@ -5,6 +5,13 @@ TODO:
- make sure things build as modules properly
- add proper arch dependencies as needed
- audit userspace interfaces to make sure they are sane
- kuid_t should never be exposed to user space as it is
kernel internal type. Data structure for this kuid_t is:
typedef struct {
uid_t val;
} kuid_t;
- This bug is introduced by Xiong Zhou in the patch bd471258f2e09
- ("staging: android: logger: use kuid_t instead of uid_t")
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
Brian Swetland <swetland@google.com>

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2008 Google, Inc.
*
* Based on, but no longer compatible with, the original
* OpenBinder.org binder driver interface, which is:
*
* Copyright (c) 2005 Palmsource, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef _LINUX_BINDER_H
#define _LINUX_BINDER_H
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
#define BINDER_IPC_32BIT 1
#endif
#include "uapi/binder.h"
#endif /* _LINUX_BINDER_H */

View File

@ -250,7 +250,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
our systems the only dma_address space is physical addresses.
Additionally, we can't afford the overhead of invalidating every
allocation via dma_map_sg. The implicit contract here is that
memory comming from the heaps is ready for dma, ie if it has a
memory coming from the heaps is ready for dma, ie if it has a
cached mapping that mapping has been invalidated */
for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
sg_dma_address(sg) = sg_phys(sg);
@ -263,8 +263,7 @@ err:
heap->ops->unmap_dma(heap, buffer);
heap->ops->free(buffer);
err1:
if (buffer->pages)
vfree(buffer->pages);
vfree(buffer->pages);
err2:
kfree(buffer);
return ERR_PTR(ret);
@ -276,8 +275,7 @@ void ion_buffer_destroy(struct ion_buffer *buffer)
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
buffer->heap->ops->unmap_dma(buffer->heap, buffer);
buffer->heap->ops->free(buffer);
if (buffer->pages)
vfree(buffer->pages);
vfree(buffer->pages);
kfree(buffer);
}
@ -902,7 +900,7 @@ void ion_pages_sync_for_device(struct device *dev, struct page *page,
sg_set_page(&sg, page, size, 0);
/*
* This is not correct - sg_dma_address needs a dma_addr_t that is valid
* for the the targeted device, but this works on the currently targeted
* for the targeted device, but this works on the currently targeted
* hardware.
*/
sg_dma_address(&sg) = page_to_phys(page);

View File

@ -76,7 +76,7 @@ struct ion_platform_data {
* size
*
* Calls memblock reserve to set aside memory for heaps that are
* located at specific memory addresses or of specfic sizes not
* located at specific memory addresses or of specific sizes not
* managed by the kernel
*/
void ion_reserve(struct ion_platform_data *data);

View File

@ -112,10 +112,8 @@ static int __init ion_dummy_init(void)
}
return 0;
err:
for (i = 0; i < dummy_ion_pdata.nr; i++) {
if (heaps[i])
ion_heap_destroy(heaps[i]);
}
for (i = 0; i < dummy_ion_pdata.nr; ++i)
ion_heap_destroy(heaps[i]);
kfree(heaps);
if (carveout_ptr) {

View File

@ -120,7 +120,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
bool high;
if (current_is_kswapd())
high = 1;
high = true;
else
high = !!(gfp_mask & __GFP_HIGHMEM);

View File

@ -345,7 +345,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
* functions for creating and destroying a heap pool -- allows you
* to keep a pool of pre allocated memory to use from your heap. Keeping
* a pool of memory that is ready for dma, ie any cached mapping have been
* invalidated from the cache, provides a significant peformance benefit on
* invalidated from the cache, provides a significant performance benefit on
* many systems */
/**
@ -362,7 +362,7 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
*
* Allows you to keep a pool of pre allocated pages to use from your heap.
* Keeping a pool of pages that is ready for dma, ie any cached mapping have
* been invalidated from the cache, provides a significant peformance benefit
* been invalidated from the cache, provides a significant performance benefit
* on many systems
*/
struct ion_page_pool {

View File

@ -54,10 +54,8 @@ static int tegra_ion_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, idev);
return 0;
err:
for (i = 0; i < num_heaps; i++) {
if (heaps[i])
ion_heap_destroy(heaps[i]);
}
for (i = 0; i < num_heaps; ++i)
ion_heap_destroy(heaps[i]);
return err;
}

View File

@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/anon_inodes.h>
#include <linux/time64.h>
#include "sync.h"
#ifdef CONFIG_DEBUG_FS
@ -95,9 +96,9 @@ static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
sync_status_str(status));
if (status <= 0) {
struct timeval tv = ktime_to_timeval(pt->base.timestamp);
struct timespec64 ts64 = ktime_to_timespec64(pt->base.timestamp);
seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
}
if (parent->ops->timeline_value_str &&

View File

@ -20,6 +20,7 @@
#include <linux/hrtimer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/ktime.h>
#include "timed_output.h"
#include "timed_gpio.h"
@ -46,16 +47,16 @@ static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
static int gpio_get_time(struct timed_output_dev *dev)
{
struct timed_gpio_data *data;
struct timeval t;
ktime_t t;
data = container_of(dev, struct timed_gpio_data, dev);
if (!hrtimer_active(&data->timer))
return 0;
t = ktime_to_timeval(hrtimer_get_remaining(&data->timer));
t = hrtimer_get_remaining(&data->timer);
return t.tv_sec * 1000 + t.tv_usec / 1000;
return ktime_to_ms(t);
}
static void gpio_enable(struct timed_output_dev *dev, int value)

View File

@ -1,474 +0,0 @@
/***********************************
* Adapter.h
************************************/
#ifndef __ADAPTER_H__
#define __ADAPTER_H__
#define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
#include "Debug.h"
struct bcm_leader {
USHORT Vcid;
USHORT PLength;
UCHAR Status;
UCHAR Unused[3];
} __packed;
struct bcm_packettosend {
struct bcm_leader Leader;
UCHAR ucPayload;
} __packed;
struct bcm_control_packet {
PVOID ControlBuff;
UINT ControlBuffLen;
struct bcm_control_packet *next;
} __packed;
struct bcm_link_request {
struct bcm_leader Leader;
UCHAR szData[4];
} __packed;
#define MAX_IP_RANGE_LENGTH 4
#define MAX_PORT_RANGE 4
#define MAX_PROTOCOL_LENGTH 32
#define IPV6_ADDRESS_SIZEINBYTES 0x10
union u_ip_address {
struct {
/* Source Ip Address Range */
ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH];
/* Source Ip Mask Address Range */
ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH];
};
struct {
/* Source Ip Address Range */
ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4];
/* Source Ip Mask Address Range */
ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4];
};
struct {
UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
};
struct {
UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
};
};
struct bcm_hdr_suppression_contextinfo {
/* Intermediate buffer to accumulate pkt Header for PHS */
UCHAR ucaHdrSuppressionInBuf[MAX_PHS_LENGTHS];
/* Intermediate buffer containing pkt Header after PHS */
UCHAR ucaHdrSuppressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN];
};
struct bcm_classifier_rule {
ULONG ulSFID;
UCHAR ucReserved[2];
B_UINT16 uiClassifierRuleIndex;
bool bUsed;
USHORT usVCID_Value;
/* This field detemines the Classifier Priority */
B_UINT8 u8ClassifierRulePriority;
union u_ip_address stSrcIpAddress;
UCHAR ucIPSourceAddressLength; /* Ip Source Address Length */
union u_ip_address stDestIpAddress;
/* Ip Destination Address Length */
UCHAR ucIPDestinationAddressLength;
UCHAR ucIPTypeOfServiceLength; /* Type of service Length */
UCHAR ucTosLow; /* Tos Low */
UCHAR ucTosHigh; /* Tos High */
UCHAR ucTosMask; /* Tos Mask */
UCHAR ucProtocolLength; /* protocol Length */
UCHAR ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */
USHORT usSrcPortRangeLo[MAX_PORT_RANGE];
USHORT usSrcPortRangeHi[MAX_PORT_RANGE];
UCHAR ucSrcPortRangeLength;
USHORT usDestPortRangeLo[MAX_PORT_RANGE];
USHORT usDestPortRangeHi[MAX_PORT_RANGE];
UCHAR ucDestPortRangeLength;
bool bProtocolValid;
bool bTOSValid;
bool bDestIpValid;
bool bSrcIpValid;
/* For IPv6 Addressing */
UCHAR ucDirection;
bool bIpv6Protocol;
UINT32 u32PHSRuleID;
struct bcm_phs_rule sPhsRule;
UCHAR u8AssociatedPHSI;
/* Classification fields for ETH CS */
UCHAR ucEthCSSrcMACLen;
UCHAR au8EThCSSrcMAC[MAC_ADDRESS_SIZE];
UCHAR au8EThCSSrcMACMask[MAC_ADDRESS_SIZE];
UCHAR ucEthCSDestMACLen;
UCHAR au8EThCSDestMAC[MAC_ADDRESS_SIZE];
UCHAR au8EThCSDestMACMask[MAC_ADDRESS_SIZE];
UCHAR ucEtherTypeLen;
UCHAR au8EthCSEtherType[NUM_ETHERTYPE_BYTES];
UCHAR usUserPriority[2];
USHORT usVLANID;
USHORT usValidityBitMap;
};
struct bcm_fragmented_packet_info {
bool bUsed;
ULONG ulSrcIpAddress;
USHORT usIpIdentification;
struct bcm_classifier_rule *pstMatchedClassifierEntry;
bool bOutOfOrderFragment;
};
struct bcm_packet_info {
/* classification extension Rule */
ULONG ulSFID;
USHORT usVCID_Value;
UINT uiThreshold;
/* This field determines the priority of the SF Queues */
B_UINT8 u8TrafficPriority;
bool bValid;
bool bActive;
bool bActivateRequestSent;
B_UINT8 u8QueueType; /* BE or rtPS */
/* maximum size of the bucket for the queue */
UINT uiMaxBucketSize;
UINT uiCurrentQueueDepthOnTarget;
UINT uiCurrentBytesOnHost;
UINT uiCurrentPacketsOnHost;
UINT uiDroppedCountBytes;
UINT uiDroppedCountPackets;
UINT uiSentBytes;
UINT uiSentPackets;
UINT uiCurrentDrainRate;
UINT uiThisPeriodSentBytes;
LARGE_INTEGER liDrainCalculated;
UINT uiCurrentTokenCount;
LARGE_INTEGER liLastUpdateTokenAt;
UINT uiMaxAllowedRate;
UINT NumOfPacketsSent;
UCHAR ucDirection;
USHORT usCID;
struct bcm_mibs_parameters stMibsExtServiceFlowTable;
UINT uiCurrentRxRate;
UINT uiThisPeriodRxBytes;
UINT uiTotalRxBytes;
UINT uiTotalTxBytes;
UINT uiPendedLast;
UCHAR ucIpVersion;
union {
struct {
struct sk_buff *FirstTxQueue;
struct sk_buff *LastTxQueue;
};
struct {
struct sk_buff *ControlHead;
struct sk_buff *ControlTail;
};
};
bool bProtocolValid;
bool bTOSValid;
bool bDestIpValid;
bool bSrcIpValid;
bool bActiveSet;
bool bAdmittedSet;
bool bAuthorizedSet;
bool bClassifierPriority;
UCHAR ucServiceClassName[MAX_CLASS_NAME_LENGTH];
bool bHeaderSuppressionEnabled;
spinlock_t SFQueueLock;
void *pstSFIndication;
struct timeval stLastUpdateTokenAt;
atomic_t uiPerSFTxResourceCount;
UINT uiMaxLatency;
UCHAR bIPCSSupport;
UCHAR bEthCSSupport;
};
struct bcm_tarang_data {
struct bcm_tarang_data *next;
struct bcm_mini_adapter *Adapter;
struct sk_buff *RxAppControlHead;
struct sk_buff *RxAppControlTail;
int AppCtrlQueueLen;
bool MacTracingEnabled;
bool bApplicationToExit;
struct bcm_mibs_dropped_cntrl_msg stDroppedAppCntrlMsgs;
ULONG RxCntrlMsgBitMask;
};
struct bcm_targetdsx_buffer {
ULONG ulTargetDsxBuffer;
B_UINT16 tid;
bool valid;
};
typedef int (*FP_FLASH_WRITE)(struct bcm_mini_adapter *, UINT, PVOID);
typedef int (*FP_FLASH_WRITE_STATUS)(struct bcm_mini_adapter *, UINT, PVOID);
/*
* Driver adapter data structure
*/
struct bcm_mini_adapter {
struct bcm_mini_adapter *next;
struct net_device *dev;
u32 msg_enable;
CHAR *caDsxReqResp;
atomic_t ApplicationRunning;
bool AppCtrlQueueOverFlow;
atomic_t CurrentApplicationCount;
atomic_t RegisteredApplicationCount;
bool LinkUpStatus;
bool TimerActive;
u32 StatisticsPointer;
struct sk_buff *RxControlHead;
struct sk_buff *RxControlTail;
struct semaphore RxAppControlQueuelock;
struct semaphore fw_download_sema;
struct bcm_tarang_data *pTarangs;
spinlock_t control_queue_lock;
wait_queue_head_t process_read_wait_queue;
/* the pointer to the first packet we have queued in send
* deserialized miniport support variables
*/
atomic_t TotalPacketCount;
atomic_t TxPktAvail;
/* this to keep track of the Tx and Rx MailBox Registers. */
atomic_t CurrNumFreeTxDesc;
/* to keep track the no of byte received */
USHORT PrevNumRecvDescs;
USHORT CurrNumRecvDescs;
UINT u32TotalDSD;
struct bcm_packet_info PackInfo[NO_OF_QUEUES];
struct bcm_classifier_rule astClassifierTable[MAX_CLASSIFIERS];
bool TransferMode;
/*************** qos ******************/
bool bETHCSEnabled;
ULONG BEBucketSize;
ULONG rtPSBucketSize;
UCHAR LinkStatus;
bool AutoLinkUp;
bool AutoSyncup;
int major;
int minor;
wait_queue_head_t tx_packet_wait_queue;
wait_queue_head_t process_rx_cntrlpkt;
atomic_t process_waiting;
bool fw_download_done;
char *txctlpacket[MAX_CNTRL_PKTS];
atomic_t cntrlpktCnt;
atomic_t index_app_read_cntrlpkt;
atomic_t index_wr_txcntrlpkt;
atomic_t index_rd_txcntrlpkt;
UINT index_datpkt;
struct semaphore rdmwrmsync;
struct bcm_targetdsx_buffer astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
ULONG ulFreeTargetBufferCnt;
ULONG ulCurrentTargetBuffer;
ULONG ulTotalTargetBuffersAvailable;
unsigned long chip_id;
wait_queue_head_t lowpower_mode_wait_queue;
bool bFlashBoot;
bool bBinDownloaded;
bool bCfgDownloaded;
bool bSyncUpRequestSent;
USHORT usBestEffortQueueIndex;
wait_queue_head_t ioctl_fw_dnld_wait_queue;
bool waiting_to_fw_download_done;
pid_t fw_download_process_pid;
struct bcm_target_params *pstargetparams;
bool device_removed;
bool DeviceAccess;
bool bIsAutoCorrectEnabled;
bool bDDRInitDone;
int DDRSetting;
ULONG ulPowerSaveMode;
spinlock_t txtransmitlock;
B_UINT8 txtransmit_running;
/* Thread for control packet handling */
struct task_struct *control_packet_handler;
/* thread for transmitting packets. */
struct task_struct *transmit_packet_thread;
/* LED Related Structures */
struct bcm_led_info LEDInfo;
/* Driver State for LED Blinking */
enum bcm_led_events DriverState;
/* Interface Specific */
PVOID pvInterfaceAdapter;
int (*bcm_file_download)(PVOID,
struct file *,
unsigned int);
int (*bcm_file_readback_from_chip)(PVOID,
struct file *,
unsigned int);
int (*interface_rdm)(PVOID,
UINT,
PVOID,
int);
int (*interface_wrm)(PVOID,
UINT,
PVOID,
int);
int (*interface_transmit)(PVOID, PVOID , UINT);
bool IdleMode;
bool bDregRequestSentInIdleMode;
bool bTriedToWakeUpFromlowPowerMode;
bool bShutStatus;
bool bWakeUpDevice;
unsigned int usIdleModePattern;
/* BOOLEAN bTriedToWakeUpFromShutdown; */
bool bLinkDownRequested;
int downloadDDR;
struct bcm_phs_extension stBCMPhsContext;
struct bcm_hdr_suppression_contextinfo stPhsTxContextInfo;
uint8_t ucaPHSPktRestoreBuf[2048];
uint8_t bPHSEnabled;
bool AutoFirmDld;
bool bMipsConfig;
bool bDPLLConfig;
UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
UINT32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
struct bcm_fragmented_packet_info
astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
atomic_t uiMBupdate;
UINT32 PmuMode;
enum bcm_nvm_type eNVMType;
UINT uiSectorSize;
UINT uiSectorSizeInCFG;
bool bSectorSizeOverride;
bool bStatusWrite;
UINT uiNVMDSDSize;
UINT uiVendorExtnFlag;
/* it will always represent chosen DSD at any point of time.
* Generally it is Active DSD but in case of NVM RD/WR it
* might be different.
*/
UINT ulFlashCalStart;
ULONG ulFlashControlSectionStart;
ULONG ulFlashWriteSize;
ULONG ulFlashID;
FP_FLASH_WRITE fpFlashWrite;
FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck;
struct semaphore NVMRdmWrmLock;
struct device *pstCreatedClassDevice;
/* BOOLEAN InterfaceUpStatus; */
struct bcm_flash2x_cs_info *psFlash2xCSInfo;
struct bcm_flash_cs_info *psFlashCSInfo;
struct bcm_flash2x_vendor_info *psFlash2xVendorInfo;
UINT uiFlashBaseAdd; /* Flash start address */
/* Active ISO offset chosen before f/w download */
UINT uiActiveISOOffset;
enum bcm_flash2x_section_val eActiveISO; /* Active ISO section val */
/* Active DSD val chosen before f/w download */
enum bcm_flash2x_section_val eActiveDSD;
/* For accessing Active DSD chosen before f/w download */
UINT uiActiveDSDOffsetAtFwDld;
UINT uiFlashLayoutMajorVersion;
UINT uiFlashLayoutMinorVersion;
bool bAllDSDWriteAllow;
bool bSigCorrupted;
/* this should be set who so ever want to change the Headers.
* after Write it should be reset immediately.
*/
bool bHeaderChangeAllowed;
int SelectedChip;
bool bEndPointHalted;
/* while bFlashRawRead will be true, Driver
* ignore map lay out and consider flash as of without any map.
*/
bool bFlashRawRead;
bool bPreparingForLowPowerMode;
bool bDoSuspend;
UINT syscfgBefFwDld;
bool StopAllXaction;
/* Used to Support extended CAPI requirements from */
UINT32 liTimeSinceLastNetEntry;
struct semaphore LowPowerModeSync;
ULONG liDrainCalculated;
UINT gpioBitMap;
struct bcm_debug_state stDebugState;
};
#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
struct bcm_eth_header {
UCHAR au8DestinationAddress[6];
UCHAR au8SourceAddress[6];
USHORT u16Etype;
} __packed;
struct bcm_firmware_info {
void __user *pvMappedFirmwareAddress;
ULONG u32FirmwareLength;
ULONG u32StartingAddress;
} __packed;
/* holds the value of net_device structure.. */
extern struct net_device *gblpnetdev;
struct bcm_ddr_setting {
UINT ulRegAddress;
UINT ulRegValue;
};
int InitAdapter(struct bcm_mini_adapter *psAdapter);
/* =====================================================================
* Beceem vendor request codes for EP0
* =====================================================================
*/
#define BCM_REQUEST_READ 0x2
#define BCM_REQUEST_WRITE 0x1
#define EP2_MPS_REG 0x0F0110A0
#define EP2_MPS 0x40
#define EP2_CFG_REG 0x0F0110A8
#define EP2_CFG_INT 0x27
#define EP2_CFG_BULK 0x25
#define EP4_MPS_REG 0x0F0110F0
#define EP4_MPS 0x8C
#define EP4_CFG_REG 0x0F0110F8
#define ISO_MPS_REG 0x0F0110C8
#define ISO_MPS 0x00000000
#define EP1 0
#define EP2 1
#define EP3 2
#define EP4 3
#define EP5 4
#define EP6 5
enum bcm_einterface_setting {
DEFAULT_SETTING_0 = 0,
ALTERNATE_SETTING_1 = 1,
};
#endif /* __ADAPTER_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,240 +0,0 @@
#include "headers.h"
struct net_device *gblpnetdev;
static INT bcm_open(struct net_device *dev)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
if (ad->fw_download_done == false) {
pr_notice(PFX "%s: link up failed (download in progress)\n",
dev->name);
return -EBUSY;
}
if (netif_msg_ifup(ad))
pr_info(PFX "%s: enabling interface\n", dev->name);
if (ad->LinkUpStatus) {
if (netif_msg_link(ad))
pr_info(PFX "%s: link up\n", dev->name);
netif_carrier_on(ad->dev);
netif_start_queue(ad->dev);
}
return 0;
}
static INT bcm_close(struct net_device *dev)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
if (netif_msg_ifdown(ad))
pr_info(PFX "%s: disabling interface\n", dev->name);
netif_carrier_off(dev);
netif_stop_queue(dev);
return 0;
}
static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb,
void *accel_priv, select_queue_fallback_t fallback)
{
return ClassifyPacket(netdev_priv(dev), skb);
}
/*******************************************************************
* Function - bcm_transmit()
*
* Description - This is the main transmit function for our virtual
* interface(eth0). It handles the ARP packets. It
* clones this packet and then Queue it to a suitable
* Queue. Then calls the transmit_packet().
*
* Parameter - skb - Pointer to the socket buffer structure
* dev - Pointer to the virtual net device structure
*
*********************************************************************/
static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
u16 qindex = skb_get_queue_mapping(skb);
if (ad->device_removed || !ad->LinkUpStatus)
goto drop;
if (ad->TransferMode != IP_PACKET_ONLY_MODE)
goto drop;
if (INVALID_QUEUE_INDEX == qindex)
goto drop;
if (ad->PackInfo[qindex].uiCurrentPacketsOnHost >=
SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
return NETDEV_TX_BUSY;
/* Now Enqueue the packet */
if (netif_msg_tx_queued(ad))
pr_info(PFX "%s: enqueueing packet to queue %d\n",
dev->name, qindex);
spin_lock(&ad->PackInfo[qindex].SFQueueLock);
ad->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
ad->PackInfo[qindex].uiCurrentPacketsOnHost++;
*((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies;
ENQUEUEPACKET(ad->PackInfo[qindex].FirstTxQueue,
ad->PackInfo[qindex].LastTxQueue, skb);
atomic_inc(&ad->TotalPacketCount);
spin_unlock(&ad->PackInfo[qindex].SFQueueLock);
/* FIXME - this is racy and incorrect, replace with work queue */
if (!atomic_read(&ad->TxPktAvail)) {
atomic_set(&ad->TxPktAvail, 1);
wake_up(&ad->tx_packet_wait_queue);
}
return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
/**
@ingroup init_functions
Register other driver entry points with the kernel
*/
static const struct net_device_ops bcmNetDevOps = {
.ndo_open = bcm_open,
.ndo_stop = bcm_close,
.ndo_start_xmit = bcm_transmit,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_select_queue = bcm_select_queue,
};
static struct device_type wimax_type = {
.name = "wimax",
};
static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = 0;
cmd->advertising = 0;
cmd->speed = SPEED_10000;
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_TP;
cmd->phy_address = 0;
cmd->transceiver = XCVR_INTERNAL;
cmd->autoneg = AUTONEG_DISABLE;
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
return 0;
}
static void bcm_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
struct bcm_interface_adapter *intf_ad = ad->pvInterfaceAdapter;
struct usb_device *udev = interface_to_usbdev(intf_ad->interface);
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u",
ad->uiFlashLayoutMajorVersion,
ad->uiFlashLayoutMinorVersion);
usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
}
static u32 bcm_get_link(struct net_device *dev)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
return ad->LinkUpStatus;
}
static u32 bcm_get_msglevel(struct net_device *dev)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
return ad->msg_enable;
}
static void bcm_set_msglevel(struct net_device *dev, u32 level)
{
struct bcm_mini_adapter *ad = GET_BCM_ADAPTER(dev);
ad->msg_enable = level;
}
static const struct ethtool_ops bcm_ethtool_ops = {
.get_settings = bcm_get_settings,
.get_drvinfo = bcm_get_drvinfo,
.get_link = bcm_get_link,
.get_msglevel = bcm_get_msglevel,
.set_msglevel = bcm_set_msglevel,
};
int register_networkdev(struct bcm_mini_adapter *ad)
{
struct net_device *net = ad->dev;
struct bcm_interface_adapter *intf_ad = ad->pvInterfaceAdapter;
struct usb_interface *udev = intf_ad->interface;
struct usb_device *xdev = intf_ad->udev;
int result;
net->netdev_ops = &bcmNetDevOps;
net->ethtool_ops = &bcm_ethtool_ops;
net->mtu = MTU_SIZE; /* 1400 Bytes */
net->tx_queue_len = TX_QLEN;
net->flags |= IFF_NOARP;
netif_carrier_off(net);
SET_NETDEV_DEVTYPE(net, &wimax_type);
/* Read the MAC Address from EEPROM */
result = ReadMacAddressFromNVM(ad);
if (result != STATUS_SUCCESS) {
dev_err(&udev->dev,
PFX "Error in Reading the mac Address: %d", result);
return -EIO;
}
result = register_netdev(net);
if (result)
return result;
gblpnetdev = ad->dev;
if (netif_msg_probe(ad))
dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n",
net->name, xdev->bus->bus_name, xdev->devpath,
net->dev_addr);
return 0;
}
void unregister_networkdev(struct bcm_mini_adapter *ad)
{
struct net_device *net = ad->dev;
struct bcm_interface_adapter *intf_ad = ad->pvInterfaceAdapter;
struct usb_interface *udev = intf_ad->interface;
struct usb_device *xdev = intf_ad->udev;
if (netif_msg_probe(ad))
dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n",
net->name, xdev->bus->bus_name, xdev->devpath);
unregister_netdev(ad->dev);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,62 +0,0 @@
/***************************************************************************
* (c) Beceem Communications Inc.
* All Rights Reserved
*
* file : CmHost.h
* author: Rajeev Tirumala
* date : September 8 , 2006
* brief : Definitions for Connection Management Requests structure
* which we will use to setup our connection structures.Its high
* time we had a header file for CmHost.cpp to isolate the way
* f/w sends DSx messages and the way we interpret them in code.
* Revision History
*
* Date Author Version Description
* 08-Sep-06 Rajeev 0.1 Created
***************************************************************************/
#ifndef _CM_HOST_H
#define _CM_HOST_H
#pragma once
#pragma pack(push, 4)
#define DSX_MESSAGE_EXCHANGE_BUFFER 0xBF60AC84 /* This contains the pointer */
#define DSX_MESSAGE_EXCHANGE_BUFFER_SIZE 72000 /* 24 K Bytes */
struct bcm_add_indication_alt {
u8 u8Type;
u8 u8Direction;
u16 u16TID;
u16 u16CID;
u16 u16VCID;
struct bcm_connect_mgr_params sfAuthorizedSet;
struct bcm_connect_mgr_params sfAdmittedSet;
struct bcm_connect_mgr_params sfActiveSet;
u8 u8CC; /* < Confirmation Code */
u8 u8Padd;
u16 u16Padd;
};
struct bcm_change_indication {
u8 u8Type;
u8 u8Direction;
u16 u16TID;
u16 u16CID;
u16 u16VCID;
struct bcm_connect_mgr_params sfAuthorizedSet;
struct bcm_connect_mgr_params sfAdmittedSet;
struct bcm_connect_mgr_params sfActiveSet;
u8 u8CC; /* < Confirmation Code */
u8 u8Padd;
u16 u16Padd;
};
unsigned long StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, void *pvBuffer, unsigned int *puBufferLength);
int AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
int FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter);
unsigned long SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter);
bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, void *pvBuffer);
#pragma pack(pop)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
#ifndef _DDR_INIT_H_
#define _DDR_INIT_H_
int ddr_init(struct bcm_mini_adapter *psAdapter);
int download_ddr_settings(struct bcm_mini_adapter *psAdapter);
#endif

View File

@ -1,242 +0,0 @@
/*
* Debug.h
*
* Dynamic (runtime) debug framework implementation.
* -kaiwan.
*/
#ifndef _DEBUG_H
#define _DEBUG_H
#include <linux/string.h>
#define NONE 0xFFFF
/* TYPE and SUBTYPE
* Define valid TYPE (or category or code-path, however you like to think of it)
* and SUBTYPE s.
* Type and SubType are treated as bitmasks.
*/
#define DBG_TYPE_INITEXIT (1 << 0) /* 1 */
#define DBG_TYPE_TX (1 << 1) /* 2 */
#define DBG_TYPE_RX (1 << 2) /* 4 */
#define DBG_TYPE_OTHERS (1 << 3) /* 8 */
#define NUMTYPES 4
/* -SUBTYPEs for TX : TYPE is DBG_TYPE_TX -----//
* Transmit.c ,Arp.c, LeakyBucket.c, And Qos.c
* total 17 macros
*/
/* Transmit.c */
#define TX 1
#define MP_SEND (TX << 0)
#define NEXT_SEND (TX << 1)
#define TX_FIFO (TX << 2)
#define TX_CONTROL (TX << 3)
/* Arp.c */
#define IP_ADDR (TX << 4)
#define ARP_REQ (TX << 5)
#define ARP_RESP (TX << 6)
/* Leakybucket.c */
#define TOKEN_COUNTS (TX << 8)
#define CHECK_TOKENS (TX << 9)
#define TX_PACKETS (TX << 10)
#define TIMER (TX << 11)
/* Qos.c */
#define QOS TX
#define QUEUE_INDEX (QOS << 12)
#define IPV4_DBG (QOS << 13)
#define IPV6_DBG (QOS << 14)
#define PRUNE_QUEUE (QOS << 15)
#define SEND_QUEUE (QOS << 16)
/* TX_Misc */
#define TX_OSAL_DBG (TX << 17)
/* --SUBTYPEs for ------INIT & EXIT---------------------
* ------------ TYPE is DBG_TYPE_INITEXIT -----//
* DriverEntry.c, bcmfwup.c, ChipDetectTask.c, HaltnReset.c, InterfaceDDR.c
*/
#define MP 1
#define DRV_ENTRY (MP << 0)
#define MP_INIT (MP << 1)
#define READ_REG (MP << 3)
#define DISPATCH (MP << 2)
#define CLAIM_ADAP (MP << 4)
#define REG_IO_PORT (MP << 5)
#define INIT_DISP (MP << 6)
#define RX_INIT (MP << 7)
/* -SUBTYPEs for --RX----------------------------------
* ------------RX : TYPE is DBG_TYPE_RX -----//
* Receive.c
*/
#define RX 1
#define RX_DPC (RX << 0)
#define RX_CTRL (RX << 3)
#define RX_DATA (RX << 4)
#define MP_RETURN (RX << 1)
#define LINK_MSG (RX << 2)
/* -SUBTYPEs for ----OTHER ROUTINES------------------
* ------------OTHERS : TYPE is DBG_TYPE_OTHER -----//
* HaltnReset,CheckForHang,PnP,Misc,CmHost
* total 12 macros
*/
#define OTHERS 1
#define ISR OTHERS
#define MP_DPC (ISR << 0)
/* HaltnReset.c */
#define HALT OTHERS
#define MP_HALT (HALT << 1)
#define CHECK_HANG (HALT << 2)
#define MP_RESET (HALT << 3)
#define MP_SHUTDOWN (HALT << 4)
/* pnp.c */
#define PNP OTHERS
#define MP_PNP (PNP << 5)
/* Misc.c */
#define MISC OTHERS
#define DUMP_INFO (MISC << 6)
#define CLASSIFY (MISC << 7)
#define LINK_UP_MSG (MISC << 8)
#define CP_CTRL_PKT (MISC << 9)
#define DUMP_CONTROL (MISC << 10)
#define LED_DUMP_INFO (MISC << 11)
/* CmHost.c */
#define CMHOST OTHERS
#define SERIAL (OTHERS << 12)
#define IDLE_MODE (OTHERS << 13)
#define WRM (OTHERS << 14)
#define RDM (OTHERS << 15)
/* TODO - put PHS_SEND in Tx PHS_RECEIVE in Rx path ? */
#define PHS_SEND (OTHERS << 16)
#define PHS_RECEIVE (OTHERS << 17)
#define PHS_MODULE (OTHERS << 18)
#define INTF_INIT (OTHERS << 19)
#define INTF_ERR (OTHERS << 20)
#define INTF_WARN (OTHERS << 21)
#define INTF_NORM (OTHERS << 22)
#define IRP_COMPLETION (OTHERS << 23)
#define SF_DESCRIPTOR_CNTS (OTHERS << 24)
#define PHS_DISPATCH (OTHERS << 25)
#define OSAL_DBG (OTHERS << 26)
#define NVM_RW (OTHERS << 27)
#define HOST_MIBS (OTHERS << 28)
#define CONN_MSG (CMHOST << 29)
/* Debug level
* We have 8 debug levels, in (numerical) increasing order of verbosity.
* IMP: Currently implementing ONLY DBG_LVL_ALL , i.e. , all debug prints will
* appear (of course, iff global debug flag is ON and we match the Type and SubType).
* Finer granularity debug levels are currently not in use, although the feature exists.
*
* Another way to say this:
* All the debug prints currently have 'debug_level' set to DBG_LVL_ALL .
* You can compile-time change that to any of the below, if you wish to. However, as of now, there's
* no dynamic facility to have the userspace 'TestApp' set debug_level. Slated for future expansion.
*/
#define BCM_ALL 7
#define BCM_LOW 6
#define BCM_PRINT 5
#define BCM_NORMAL 4
#define BCM_MEDIUM 3
#define BCM_SCREAM 2
#define BCM_ERR 1
/* Not meant for developer in debug prints.
* To be used to disable all prints by setting the DBG_LVL_CURR to this value
*/
#define BCM_NONE 0
/* The current driver logging level.
* Everything at this level and (numerically) lower (meaning higher prio)
* is logged.
* Replace 'BCM_ALL' in the DBG_LVL_CURR macro with the logging level desired.
* For eg. to set the logging level to 'errors only' use:
* #define DBG_LVL_CURR (BCM_ERR)
*/
#define DBG_LVL_CURR (BCM_ALL)
#define DBG_LVL_ALL BCM_ALL
/* ---Userspace mapping of Debug State.
* Delibrately matches that of the Windows driver..
* The TestApp's ioctl passes this struct to us.
*/
struct bcm_user_debug_state {
unsigned int Subtype, Type;
unsigned int OnOff;
/* unsigned int debug_level; future expansion */
} __packed;
/* ---Kernel-space mapping of Debug State */
struct bcm_debug_state {
unsigned int type;
/* A bitmap of 32 bits for Subtype per Type.
* Valid indexes in 'subtype' array are *only* 1,2,4 and 8,
* corresponding to valid Type values. Hence we use the 'Type' field
* as the index value, ignoring the array entries 0,3,5,6,7 !
*/
unsigned int subtype[(NUMTYPES*2)+1];
unsigned int debug_level;
};
/* Instantiated in the Adapter structure
* We'll reuse the debug level parameter to include a bit (the MSB) to indicate whether or not
* we want the function's name printed.
*/
#define DBG_NO_FUNC_PRINT (1 << 31)
#define DBG_LVL_BITMASK 0xFF
/* --- Only for direct printk's; "hidden" to API. */
#define DBG_TYPE_PRINTK 3
#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \
do { \
if (DBG_TYPE_PRINTK == Type) \
pr_info("%s:" string, __func__, ##args); \
else if (Adapter && \
(dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \
(Type & Adapter->stDebugState.type) && \
(SubType & Adapter->stDebugState.subtype[Type])) { \
if (dbg_level & DBG_NO_FUNC_PRINT) \
pr_debug("%s:\n", string); \
else \
pr_debug("%s:\n" string, __func__, ##args); \
} \
} while (0)
#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) \
do { \
if (DBG_TYPE_PRINTK == Type || \
(Adapter && \
(dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \
(Type & Adapter->stDebugState.type) && \
(SubType & Adapter->stDebugState.subtype[Type]))) { \
pr_debug("%s:\n", __func__); \
print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, \
16, 1, buffer, bufferlen, false); \
} \
} while (0)
#define BCM_SHOW_DEBUG_BITMAP(Adapter) do { \
int i; \
for (i = 0; i < (NUMTYPES * 2) + 1; i++) { \
if ((i == 1) || (i == 2) || (i == 4) || (i == 8)) { \
/* CAUTION! Forcefully turn on ALL debug paths and subpaths! \
* Adapter->stDebugState.subtype[i] = 0xffffffff; \
*/ \
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "subtype[%d] = 0x%08x\n", \
i, Adapter->stDebugState.subtype[i]); \
} \
} \
} while (0)
#endif

View File

@ -1,241 +0,0 @@
/**
* @file HandleControlPacket.c
* This file contains the routines to deal with
* sending and receiving of control packets.
*/
#include "headers.h"
/**
* When a control packet is received, analyze the
* "status" and call appropriate response function.
* Enqueue the control packet for Application.
* @return None
*/
static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter,
struct sk_buff *skb)
{
struct bcm_tarang_data *pTarang = NULL;
bool HighPriorityMessage = false;
struct sk_buff *newPacket = NULL;
CHAR cntrl_msg_mask_bit = 0;
bool drop_pkt_flag = TRUE;
USHORT usStatus = *(PUSHORT)(skb->data);
if (netif_msg_pktdata(Adapter))
print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE,
16, 1, skb->data, skb->len, 0);
switch (usStatus) {
case CM_RESPONSES: /* 0xA0 */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT,
DBG_LVL_ALL,
"MAC Version Seems to be Non Multi-Classifier, rejected by Driver");
HighPriorityMessage = TRUE;
break;
case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP:
HighPriorityMessage = TRUE;
if (Adapter->LinkStatus == LINKUP_DONE)
CmControlResponseMessage(Adapter,
(skb->data + sizeof(USHORT)));
break;
case LINK_CONTROL_RESP: /* 0xA2 */
case STATUS_RSP: /* 0xA1 */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT,
DBG_LVL_ALL, "LINK_CONTROL_RESP");
HighPriorityMessage = TRUE;
LinkControlResponseMessage(Adapter,
(skb->data + sizeof(USHORT)));
break;
case STATS_POINTER_RESP: /* 0xA6 */
HighPriorityMessage = TRUE;
StatisticsResponse(Adapter, (skb->data + sizeof(USHORT)));
break;
case IDLE_MODE_STATUS: /* 0xA3 */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT,
DBG_LVL_ALL,
"IDLE_MODE_STATUS Type Message Got from F/W");
InterfaceIdleModeRespond(Adapter, (PUINT)(skb->data +
sizeof(USHORT)));
HighPriorityMessage = TRUE;
break;
case AUTH_SS_HOST_MSG:
HighPriorityMessage = TRUE;
break;
default:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT,
DBG_LVL_ALL, "Got Default Response");
/* Let the Application Deal with This Packet */
break;
}
/* Queue The Control Packet to The Application Queues */
down(&Adapter->RxAppControlQueuelock);
for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) {
if (Adapter->device_removed)
break;
drop_pkt_flag = TRUE;
/*
* There are cntrl msg from A0 to AC. It has been mapped to 0 to
* C bit in the cntrl mask.
* Also, by default AD to BF has been masked to the rest of the
* bits... which wil be ON by default.
* if mask bit is enable to particular pkt status, send it out
* to app else stop it.
*/
cntrl_msg_mask_bit = (usStatus & 0x1F);
/*
* printk("\ninew msg mask bit which is disable in mask:%X",
* cntrl_msg_mask_bit);
*/
if (pTarang->RxCntrlMsgBitMask & (1 << cntrl_msg_mask_bit))
drop_pkt_flag = false;
if ((drop_pkt_flag == TRUE) ||
(pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN)
|| ((pTarang->AppCtrlQueueLen >
MAX_APP_QUEUE_LEN / 2) &&
(HighPriorityMessage == false))) {
/*
* Assumption:-
* 1. every tarang manages it own dropped pkt
* statitistics
* 2. Total packet dropped per tarang will be equal to
* the sum of all types of dropped pkt by that
* tarang only.
*/
struct bcm_mibs_dropped_cntrl_msg *msg =
&pTarang->stDroppedAppCntrlMsgs;
switch (*(PUSHORT)skb->data) {
case CM_RESPONSES:
msg->cm_responses++;
break;
case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP:
msg->cm_control_newdsx_multiclassifier_resp++;
break;
case LINK_CONTROL_RESP:
msg->link_control_resp++;
break;
case STATUS_RSP:
msg->status_rsp++;
break;
case STATS_POINTER_RESP:
msg->stats_pointer_resp++;
break;
case IDLE_MODE_STATUS:
msg->idle_mode_status++;
break;
case AUTH_SS_HOST_MSG:
msg->auth_ss_host_msg++;
break;
default:
msg->low_priority_message++;
break;
}
continue;
}
newPacket = skb_clone(skb, GFP_KERNEL);
if (!newPacket)
break;
ENQUEUEPACKET(pTarang->RxAppControlHead,
pTarang->RxAppControlTail, newPacket);
pTarang->AppCtrlQueueLen++;
}
up(&Adapter->RxAppControlQueuelock);
wake_up(&Adapter->process_read_wait_queue);
dev_kfree_skb(skb);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL,
"After wake_up_interruptible");
}
/**
* @ingroup ctrl_pkt_functions
* Thread to handle control pkt reception
*/
/* pointer to adapter object*/
int control_packet_handler(struct bcm_mini_adapter *Adapter)
{
struct sk_buff *ctrl_packet = NULL;
unsigned long flags = 0;
/* struct timeval tv; */
/* int *puiBuffer = NULL; */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL,
"Entering to make thread wait on control packet event!");
while (1) {
wait_event_interruptible(Adapter->process_rx_cntrlpkt,
atomic_read(&Adapter->cntrlpktCnt) ||
Adapter->bWakeUpDevice ||
kthread_should_stop());
if (kthread_should_stop()) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT,
DBG_LVL_ALL, "Exiting\n");
return 0;
}
if (TRUE == Adapter->bWakeUpDevice) {
Adapter->bWakeUpDevice = false;
if ((false == Adapter->bTriedToWakeUpFromlowPowerMode)
&& ((TRUE == Adapter->IdleMode) ||
(TRUE == Adapter->bShutStatus))) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
CP_CTRL_PKT, DBG_LVL_ALL,
"Calling InterfaceAbortIdlemode\n");
/*
* Adapter->bTriedToWakeUpFromlowPowerMode
* = TRUE;
*/
InterfaceIdleModeWakeup(Adapter);
}
continue;
}
while (atomic_read(&Adapter->cntrlpktCnt)) {
spin_lock_irqsave(&Adapter->control_queue_lock, flags);
ctrl_packet = Adapter->RxControlHead;
if (ctrl_packet) {
DEQUEUEPACKET(Adapter->RxControlHead,
Adapter->RxControlTail);
/* Adapter->RxControlHead=ctrl_packet->next; */
}
spin_unlock_irqrestore(&Adapter->control_queue_lock,
flags);
handle_rx_control_packet(Adapter, ctrl_packet);
atomic_dec(&Adapter->cntrlpktCnt);
}
SetUpTargetDsxBuffers(Adapter);
}
return STATUS_SUCCESS;
}
INT flushAllAppQ(void)
{
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
struct bcm_tarang_data *pTarang = NULL;
struct sk_buff *PacketToDrop = NULL;
for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) {
while (pTarang->RxAppControlHead != NULL) {
PacketToDrop = pTarang->RxAppControlHead;
DEQUEUEPACKET(pTarang->RxAppControlHead,
pTarang->RxAppControlTail);
dev_kfree_skb(PacketToDrop);
}
pTarang->AppCtrlQueueLen = 0;
/* dropped contrl packet statistics also should be reset. */
memset((PVOID)&pTarang->stDroppedAppCntrlMsgs, 0,
sizeof(struct bcm_mibs_dropped_cntrl_msg));
}
return STATUS_SUCCESS;
}

View File

@ -1,192 +0,0 @@
#ifndef _HOST_MIBSINTERFACE_H
#define _HOST_MIBSINTERFACE_H
/*
* Copyright (c) 2007 Beceem Communications Pvt. Ltd
* File Name: HostMIBSInterface.h
* Abstract: This file contains DS used by the Host to update the Host
* statistics used for the MIBS.
*/
#define MIBS_MAX_CLASSIFIERS 100
#define MIBS_MAX_PHSRULES 100
#define MIBS_MAX_SERVICEFLOWS 17
#define MIBS_MAX_IP_RANGE_LENGTH 4
#define MIBS_MAX_PORT_RANGE 4
#define MIBS_MAX_PROTOCOL_LENGTH 32
#define MIBS_MAX_PHS_LENGTHS 255
#define MIBS_IPV6_ADDRESS_SIZEINBYTES 0x10
#define MIBS_IP_LENGTH_OF_ADDRESS 4
#define MIBS_MAX_HIST_ENTRIES 12
#define MIBS_PKTSIZEHIST_RANGE 128
union bcm_mibs_ip_addr {
struct {
/* Source Ip Address Range */
unsigned long ulIpv4Addr[MIBS_MAX_IP_RANGE_LENGTH];
/* Source Ip Mask Address Range */
unsigned long ulIpv4Mask[MIBS_MAX_IP_RANGE_LENGTH];
};
struct {
/* Source Ip Address Range */
unsigned long ulIpv6Addr[MIBS_MAX_IP_RANGE_LENGTH * 4];
/* Source Ip Mask Address Range */
unsigned long ulIpv6Mask[MIBS_MAX_IP_RANGE_LENGTH * 4];
};
struct {
unsigned char ucIpv4Address[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IP_LENGTH_OF_ADDRESS];
unsigned char ucIpv4Mask[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IP_LENGTH_OF_ADDRESS];
};
struct {
unsigned char ucIpv6Address[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IPV6_ADDRESS_SIZEINBYTES];
unsigned char ucIpv6Mask[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IPV6_ADDRESS_SIZEINBYTES];
};
};
struct bcm_mibs_host_info {
u64 GoodTransmits;
u64 GoodReceives;
/* this to keep track of the Tx and Rx MailBox Registers. */
unsigned long NumDesUsed;
unsigned long CurrNumFreeDesc;
unsigned long PrevNumFreeDesc;
/* to keep track the no of byte received */
unsigned long PrevNumRcevBytes;
unsigned long CurrNumRcevBytes;
/* QOS Related */
unsigned long BEBucketSize;
unsigned long rtPSBucketSize;
unsigned long LastTxQueueIndex;
bool TxOutofDescriptors;
bool TimerActive;
u32 u32TotalDSD;
u32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
u32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
};
struct bcm_mibs_classifier_rule {
unsigned long ulSFID;
unsigned char ucReserved[2];
u16 uiClassifierRuleIndex;
bool bUsed;
unsigned short usVCID_Value;
u8 u8ClassifierRulePriority;
union bcm_mibs_ip_addr stSrcIpAddress;
/* IP Source Address Length */
unsigned char ucIPSourceAddressLength;
union bcm_mibs_ip_addr stDestIpAddress;
/* IP Destination Address Length */
unsigned char ucIPDestinationAddressLength;
unsigned char ucIPTypeOfServiceLength;
unsigned char ucTosLow;
unsigned char ucTosHigh;
unsigned char ucTosMask;
unsigned char ucProtocolLength;
unsigned char ucProtocol[MIBS_MAX_PROTOCOL_LENGTH];
unsigned short usSrcPortRangeLo[MIBS_MAX_PORT_RANGE];
unsigned short usSrcPortRangeHi[MIBS_MAX_PORT_RANGE];
unsigned char ucSrcPortRangeLength;
unsigned short usDestPortRangeLo[MIBS_MAX_PORT_RANGE];
unsigned short usDestPortRangeHi[MIBS_MAX_PORT_RANGE];
unsigned char ucDestPortRangeLength;
bool bProtocolValid;
bool bTOSValid;
bool bDestIpValid;
bool bSrcIpValid;
unsigned char ucDirection;
bool bIpv6Protocol;
u32 u32PHSRuleID;
};
struct bcm_mibs_phs_rule {
unsigned long ulSFID;
u8 u8PHSI;
u8 u8PHSFLength;
u8 u8PHSF[MIBS_MAX_PHS_LENGTHS];
u8 u8PHSMLength;
u8 u8PHSM[MIBS_MAX_PHS_LENGTHS];
u8 u8PHSS;
u8 u8PHSV;
u8 reserved[5];
long PHSModifiedBytes;
unsigned long PHSModifiedNumPackets;
unsigned long PHSErrorNumPackets;
};
struct bcm_mibs_parameters {
u32 wmanIfSfid;
u32 wmanIfCmnCpsSfState;
u32 wmanIfCmnCpsMaxSustainedRate;
u32 wmanIfCmnCpsMaxTrafficBurst;
u32 wmanIfCmnCpsMinReservedRate;
u32 wmanIfCmnCpsToleratedJitter;
u32 wmanIfCmnCpsMaxLatency;
u32 wmanIfCmnCpsFixedVsVariableSduInd;
u32 wmanIfCmnCpsSduSize;
u32 wmanIfCmnCpsSfSchedulingType;
u32 wmanIfCmnCpsArqEnable;
u32 wmanIfCmnCpsArqWindowSize;
u32 wmanIfCmnCpsArqBlockLifetime;
u32 wmanIfCmnCpsArqSyncLossTimeout;
u32 wmanIfCmnCpsArqDeliverInOrder;
u32 wmanIfCmnCpsArqRxPurgeTimeout;
u32 wmanIfCmnCpsArqBlockSize;
u32 wmanIfCmnCpsMinRsvdTolerableRate;
u32 wmanIfCmnCpsReqTxPolicy;
u32 wmanIfCmnSfCsSpecification;
u32 wmanIfCmnCpsTargetSaid;
};
struct bcm_mibs_table {
unsigned long ulSFID;
unsigned short usVCID_Value;
unsigned int uiThreshold;
u8 u8TrafficPriority;
bool bValid;
bool bActive;
bool bActivateRequestSent;
u8 u8QueueType;
unsigned int uiMaxBucketSize;
unsigned int uiCurrentQueueDepthOnTarget;
unsigned int uiCurrentBytesOnHost;
unsigned int uiCurrentPacketsOnHost;
unsigned int uiDroppedCountBytes;
unsigned int uiDroppedCountPackets;
unsigned int uiSentBytes;
unsigned int uiSentPackets;
unsigned int uiCurrentDrainRate;
unsigned int uiThisPeriodSentBytes;
u64 liDrainCalculated;
unsigned int uiCurrentTokenCount;
u64 liLastUpdateTokenAt;
unsigned int uiMaxAllowedRate;
unsigned int NumOfPacketsSent;
unsigned char ucDirection;
unsigned short usCID;
struct bcm_mibs_parameters stMibsExtServiceFlowTable;
unsigned int uiCurrentRxRate;
unsigned int uiThisPeriodRxBytes;
unsigned int uiTotalRxBytes;
unsigned int uiTotalTxBytes;
};
struct bcm_mibs_dropped_cntrl_msg {
unsigned long cm_responses;
unsigned long cm_control_newdsx_multiclassifier_resp;
unsigned long link_control_resp;
unsigned long status_rsp;
unsigned long stats_pointer_resp;
unsigned long idle_mode_status;
unsigned long auth_ss_host_msg;
unsigned long low_priority_message;
};
struct bcm_host_stats_mibs {
struct bcm_mibs_host_info stHostInfo;
struct bcm_mibs_classifier_rule astClassifierTable[MIBS_MAX_CLASSIFIERS];
struct bcm_mibs_table astSFtable[MIBS_MAX_SERVICEFLOWS];
struct bcm_mibs_phs_rule astPhsRulesTable[MIBS_MAX_PHSRULES];
struct bcm_mibs_dropped_cntrl_msg stDroppedAppCntrlMsgs;
};
#endif

View File

@ -1,476 +0,0 @@
#include "headers.h"
static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
struct bcm_ipv6_hdr *pstIpv6Header);
static bool MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
struct bcm_ipv6_hdr *pstIpv6Header);
static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header);
static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
UCHAR *pucNextHeader, bool *bParseDone, USHORT *pusPayloadLength)
{
UCHAR *pucRetHeaderPtr = NULL;
UCHAR *pucPayloadPtr = NULL;
USHORT usNextHeaderOffset = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
(*bParseDone)) {
*bParseDone = TRUE;
return NULL;
}
pucRetHeaderPtr = *ppucPayload;
pucPayloadPtr = *ppucPayload;
if (!pucRetHeaderPtr || !pucPayloadPtr) {
*bParseDone = TRUE;
return NULL;
}
/* Get the Nextt Header Type */
*bParseDone = false;
switch (*pucNextHeader) {
case IPV6HDR_TYPE_HOPBYHOP:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nIPv6 HopByHop Header");
usNextHeaderOffset += sizeof(struct bcm_ipv6_options_hdr);
break;
case IPV6HDR_TYPE_ROUTING:
{
struct bcm_ipv6_routing_hdr *pstIpv6RoutingHeader;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nIPv6 Routing Header");
pstIpv6RoutingHeader =
(struct bcm_ipv6_routing_hdr *)pucPayloadPtr;
usNextHeaderOffset += sizeof(struct bcm_ipv6_routing_hdr);
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses *
IPV6_ADDRESS_SIZEINBYTES;
}
break;
case IPV6HDR_TYPE_FRAGMENTATION:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 Fragmentation Header");
usNextHeaderOffset += sizeof(struct bcm_ipv6_fragment_hdr);
break;
case IPV6HDR_TYPE_DESTOPTS:
{
struct bcm_ipv6_dest_options_hdr *pstIpv6DestOptsHdr =
(struct bcm_ipv6_dest_options_hdr *)pucPayloadPtr;
int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 DestOpts Header Header");
usNextHeaderOffset += sizeof(struct bcm_ipv6_dest_options_hdr);
usNextHeaderOffset += nTotalOptions *
IPV6_DESTOPTS_HDR_OPTIONSIZE;
}
break;
case IPV6HDR_TYPE_AUTHENTICATION:
{
struct bcm_ipv6_authentication_hdr *pstIpv6AuthHdr =
(struct bcm_ipv6_authentication_hdr *)pucPayloadPtr;
int nHdrLen = pstIpv6AuthHdr->ucLength;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 Authentication Header");
usNextHeaderOffset += nHdrLen * 4;
}
break;
case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 Encrypted Security Payload Header");
*bParseDone = TRUE;
break;
case IPV6_ICMP_HDR_TYPE:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nICMP Header");
*bParseDone = TRUE;
break;
case TCP_HEADER_TYPE:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nTCP Header");
*bParseDone = TRUE;
break;
case UDP_HEADER_TYPE:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nUDP Header");
*bParseDone = TRUE;
break;
default:
*bParseDone = TRUE;
break;
}
if (*bParseDone == false) {
if (*pusPayloadLength <= usNextHeaderOffset) {
*bParseDone = TRUE;
} else {
*pucNextHeader = *pucPayloadPtr;
pucPayloadPtr += usNextHeaderOffset;
(*pusPayloadLength) -= usNextHeaderOffset;
}
}
*ppucPayload = pucPayloadPtr;
return pucRetHeaderPtr;
}
static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader)
{
UCHAR *pIpv6HdrScanContext = pucPayload;
bool bDone = false;
UCHAR ucHeaderType = 0;
UCHAR *pucNextHeader = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
if (!pucPayload || (usPayloadLength == 0))
return 0;
*pusSrcPort = *pusDestPort = 0;
ucHeaderType = ucNextHeader;
while (!bDone) {
pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,
&ucHeaderType,
&bDone,
&usPayloadLength);
if (bDone) {
if ((ucHeaderType == TCP_HEADER_TYPE) ||
(ucHeaderType == UDP_HEADER_TYPE)) {
*pusSrcPort = *((PUSHORT)(pucNextHeader));
*pusDestPort = *((PUSHORT)(pucNextHeader+2));
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",
ntohs(*pusSrcPort),
ntohs(*pusDestPort));
}
break;
}
}
return ucHeaderType;
}
/*
* Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver control
* structure
* Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
*/
USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
struct bcm_classifier_rule *pstClassifierRule)
{
USHORT ushDestPort = 0;
USHORT ushSrcPort = 0;
UCHAR ucNextProtocolAboveIP = 0;
struct bcm_ipv6_hdr *pstIpv6Header = NULL;
bool bClassificationSucceed = false;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "IpVersion6 ==========>\n");
pstIpv6Header = pcIpHeader;
DumpIpv6Header(pstIpv6Header);
/*
* Try to get the next higher layer protocol
* and the Ports Nos if TCP or UDP
*/
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader +
sizeof(struct bcm_ipv6_hdr)),
&ushSrcPort,
&ushDestPort,
pstIpv6Header->usPayloadLength,
pstIpv6Header->ucNextHeader);
do {
if (pstClassifierRule->ucDirection == 0) {
/*
* cannot be processed for classification.
* it is a down link connection
*/
break;
}
if (!pstClassifierRule->bIpv6Protocol) {
/*
* We are looking for Ipv6 Classifiers
* Lets ignore this classifier and try the next one
*/
break;
}
bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule,
pstIpv6Header);
if (!bClassificationSucceed)
break;
bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule,
pstIpv6Header);
if (!bClassificationSucceed)
break;
/*
* Match the protocol type.
* For IPv6 the next protocol at end of
* Chain of IPv6 prot headers
*/
bClassificationSucceed = MatchProtocol(pstClassifierRule,
ucNextProtocolAboveIP);
if (!bClassificationSucceed)
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nIPv6 Protocol Matched");
if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) ||
(ucNextProtocolAboveIP == UDP_HEADER_TYPE)) {
/* Match Src Port */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",
ntohs(ushSrcPort));
bClassificationSucceed = MatchSrcPort(pstClassifierRule,
ntohs(ushSrcPort));
if (!bClassificationSucceed)
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL, "\nIPv6 Src Port Matched");
/* Match Dest Port */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 Destination Port:%x\n",
ntohs(ushDestPort));
bClassificationSucceed = MatchDestPort(pstClassifierRule,
ntohs(ushDestPort));
if (!bClassificationSucceed)
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"\nIPv6 Dest Port Matched");
}
} while (0);
if (bClassificationSucceed == TRUE) {
INT iMatchedSFQueueIndex = 0;
iMatchedSFQueueIndex = SearchSfid(Adapter,
pstClassifierRule->ulSFID);
if ((iMatchedSFQueueIndex >= NO_OF_QUEUES) ||
(Adapter->PackInfo[iMatchedSFQueueIndex].bActive == false))
bClassificationSucceed = false;
}
return bClassificationSucceed;
}
static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
struct bcm_ipv6_hdr *pstIpv6Header)
{
UINT uiLoopIndex = 0;
UINT uiIpv6AddIndex = 0;
UINT uiIpv6AddrNoLongWords = 4;
ULONG aulSrcIP[4];
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
union u_ip_address *src_addr = &pstClassifierRule->stSrcIpAddress;
/*
* This is the no. of Src Addresses ie Range of IP Addresses contained
* in the classifier rule for which we need to match
*/
UINT uiCountIPSrcAddresses =
(UINT)pstClassifierRule->ucIPSourceAddressLength;
if (uiCountIPSrcAddresses == 0)
return TRUE;
/* First Convert the Ip Address in the packet to Host Endian order */
for (uiIpv6AddIndex = 0;
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
uiIpv6AddIndex++)
aulSrcIP[uiIpv6AddIndex] =
ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
for (uiLoopIndex = 0;
uiLoopIndex < uiCountIPSrcAddresses;
uiLoopIndex += uiIpv6AddrNoLongWords) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Src Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulSrcIP);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Src Ipv6 Mask In Classifier Rule:\n");
DumpIpv6Address(&src_addr->ulIpv6Mask[uiLoopIndex]);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Src Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&src_addr->ulIpv6Addr[uiLoopIndex]);
for (uiIpv6AddIndex = 0;
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
uiIpv6AddIndex++) {
if ((src_addr->ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] &
aulSrcIP[uiIpv6AddIndex]) !=
src_addr->ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
/*
* Match failed for current Ipv6 Address
* Try next Ipv6 Address
*/
break;
}
if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
/* Match Found */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"Ipv6 Src Ip Address Matched\n");
return TRUE;
}
}
}
return false;
}
static bool MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
struct bcm_ipv6_hdr *pstIpv6Header)
{
UINT uiLoopIndex = 0;
UINT uiIpv6AddIndex = 0;
UINT uiIpv6AddrNoLongWords = 4;
ULONG aulDestIP[4];
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
union u_ip_address *dest_addr = &pstClassifierRule->stDestIpAddress;
/*
* This is the no. of Destination Addresses
* ie Range of IP Addresses contained in the classifier rule
* for which we need to match
*/
UINT uiCountIPDestinationAddresses =
(UINT)pstClassifierRule->ucIPDestinationAddressLength;
if (uiCountIPDestinationAddresses == 0)
return TRUE;
/* First Convert the Ip Address in the packet to Host Endian order */
for (uiIpv6AddIndex = 0;
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
uiIpv6AddIndex++)
aulDestIP[uiIpv6AddIndex] =
ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
for (uiLoopIndex = 0;
uiLoopIndex < uiCountIPDestinationAddresses;
uiLoopIndex += uiIpv6AddrNoLongWords) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Destination Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulDestIP);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Destination Ipv6 Mask In Classifier Rule :\n");
DumpIpv6Address(&dest_addr->ulIpv6Mask[uiLoopIndex]);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"\n Destination Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&dest_addr->ulIpv6Addr[uiLoopIndex]);
for (uiIpv6AddIndex = 0;
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
uiIpv6AddIndex++) {
if ((dest_addr->ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] &
aulDestIP[uiIpv6AddIndex]) !=
dest_addr->ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
/*
* Match failed for current Ipv6 Address.
* Try next Ipv6 Address
*/
break;
}
if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
/* Match Found */
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
DBG_LVL_ALL,
"Ipv6 Destination Ip Address Matched\n");
return TRUE;
}
}
}
return false;
}
VOID DumpIpv6Address(ULONG *puIpv6Address)
{
UINT uiIpv6AddrNoLongWords = 4;
UINT uiIpv6AddIndex = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
for (uiIpv6AddIndex = 0;
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
uiIpv6AddIndex++) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
":%lx", puIpv6Address[uiIpv6AddIndex]);
}
}
static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header)
{
UCHAR ucVersion;
UCHAR ucPrio;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"----Ipv6 Header---");
ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Version : %x\n", ucVersion);
ucPrio = pstIpv6Header->ucVersionPrio & 0x0f;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Priority : %x\n", ucPrio);
/*
* BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
* "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0);
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Payload Length : %x\n",
ntohs(pstIpv6Header->usPayloadLength));
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Next Header : %x\n", pstIpv6Header->ucNextHeader);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Hop Limit : %x\n", pstIpv6Header->ucHopLimit);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Src Address :\n");
DumpIpv6Address(pstIpv6Header->ulSrcIpAddress);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"Dest Address :\n");
DumpIpv6Address(pstIpv6Header->ulDestIpAddress);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
"----Ipv6 Header End---");
}

View File

@ -1,85 +0,0 @@
#ifndef _IPV6_PROTOCOL_DEFINES_
#define _IPV6_PROTOCOL_DEFINES_
#define IPV6HDR_TYPE_HOPBYHOP 0x0
#define IPV6HDR_TYPE_ROUTING 0x2B
#define IPV6HDR_TYPE_FRAGMENTATION 0x2C
#define IPV6HDR_TYPE_DESTOPTS 0x3c
#define IPV6HDR_TYPE_AUTHENTICATION 0x33
#define IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD 0x34
#define MASK_IPV6_CS_SPEC 0x2
#define TCP_HEADER_TYPE 0x6
#define UDP_HEADER_TYPE 0x11
#define IPV6_ICMP_HDR_TYPE 0x2
#define IPV6_FLOWLABEL_BITOFFSET 9
#define IPV6_MAX_CHAINEDHDR_BUFFBYTES 0x64
/*
* Size of Dest Options field of Destinations Options Header
* in bytes.
*/
#define IPV6_DESTOPTS_HDR_OPTIONSIZE 0x8
struct bcm_ipv6_hdr {
unsigned char ucVersionPrio;
unsigned char aucFlowLabel[3];
unsigned short usPayloadLength;
unsigned char ucNextHeader;
unsigned char ucHopLimit;
unsigned long ulSrcIpAddress[4];
unsigned long ulDestIpAddress[4];
};
struct bcm_ipv6_routing_hdr {
unsigned char ucNextHeader;
unsigned char ucRoutingType;
unsigned char ucNumAddresses;
unsigned char ucNextAddress;
unsigned long ulReserved;
};
struct bcm_ipv6_fragment_hdr {
unsigned char ucNextHeader;
unsigned char ucReserved;
unsigned short usFragmentOffset;
unsigned long ulIdentification;
};
struct bcm_ipv6_dest_options_hdr {
unsigned char ucNextHeader;
unsigned char ucHdrExtLen;
unsigned char ucDestOptions[6];
};
struct bcm_ipv6_options_hdr {
unsigned char ucNextHeader;
unsigned char ucMisc[3];
unsigned long ulJumboPayloadLen;
};
struct bcm_ipv6_authentication_hdr {
unsigned char ucNextHeader;
unsigned char ucLength;
unsigned short usReserved;
unsigned long ulSecurityParametersIndex;
};
enum bcm_ipaddr_context {
eSrcIpAddress,
eDestIpAddress
};
/* Function Prototypes */
unsigned short IpVersion6(struct bcm_mini_adapter *Adapter, /* < Pointer to the driver control structure */
void *pcIpHeader, /* <Pointer to the IP Hdr of the packet */
struct bcm_classifier_rule *pstClassifierRule);
void DumpIpv6Address(unsigned long *puIpv6Address);
extern bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, unsigned short ushSrcPort);
extern bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, unsigned short ushSrcPort);
extern bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, unsigned char ucProtocol);
#endif

View File

@ -1,79 +0,0 @@
#ifndef _INTERFACE_ADAPTER_H
#define _INTERFACE_ADAPTER_H
struct bcm_bulk_endpoint_in {
char *bulk_in_buffer;
size_t bulk_in_size;
unsigned char bulk_in_endpointAddr;
unsigned int bulk_in_pipe;
};
struct bcm_bulk_endpoint_out {
unsigned char bulk_out_buffer;
size_t bulk_out_size;
unsigned char bulk_out_endpointAddr;
unsigned int bulk_out_pipe;
/* this is used when int out endpoint is used as bulk out end point */
unsigned char int_out_interval;
};
struct bcm_intr_endpoint_in {
char *int_in_buffer;
size_t int_in_size;
unsigned char int_in_endpointAddr;
unsigned char int_in_interval;
unsigned int int_in_pipe;
};
struct bcm_intr_endpoint_out {
char *int_out_buffer;
size_t int_out_size;
unsigned char int_out_endpointAddr;
unsigned char int_out_interval;
unsigned int int_out_pipe;
};
struct bcm_usb_tcb {
struct urb *urb;
void *psIntfAdapter;
bool bUsed;
};
struct bcm_usb_rcb {
struct urb *urb;
void *psIntfAdapter;
bool bUsed;
};
/*
* This is the interface specific Sub-Adapter
* Structure.
*/
struct bcm_interface_adapter {
struct usb_device *udev;
struct usb_interface *interface;
/* Bulk endpoint in info */
struct bcm_bulk_endpoint_in sBulkIn;
/* Bulk endpoint out info */
struct bcm_bulk_endpoint_out sBulkOut;
/* Interrupt endpoint in info */
struct bcm_intr_endpoint_in sIntrIn;
/* Interrupt endpoint out info */
struct bcm_intr_endpoint_out sIntrOut;
unsigned long ulInterruptData[2];
struct urb *psInterruptUrb;
struct bcm_usb_tcb asUsbTcb[MAXIMUM_USB_TCB];
struct bcm_usb_rcb asUsbRcb[MAXIMUM_USB_RCB];
atomic_t uNumTcbUsed;
atomic_t uCurrTcb;
atomic_t uNumRcbUsed;
atomic_t uCurrRcb;
struct bcm_mini_adapter *psAdapter;
bool bFlashBoot;
bool bHighSpeedDevice;
bool bSuspended;
bool bPreparingForBusSuspend;
struct work_struct usbSuspendWork;
};
#endif

View File

@ -1,317 +0,0 @@
#include "headers.h"
int InterfaceFileDownload(PVOID arg, struct file *flp, unsigned int on_chip_loc)
{
/* unsigned int reg = 0; */
mm_segment_t oldfs = {0};
int errno = 0, len = 0; /* ,is_config_file = 0 */
loff_t pos = 0;
struct bcm_interface_adapter *psIntfAdapter = arg;
/* struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; */
char *buff = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
if (!buff)
return -ENOMEM;
while (1) {
oldfs = get_fs();
set_fs(get_ds());
len = vfs_read(flp, (void __force __user *)buff,
MAX_TRANSFER_CTRL_BYTE_USB, &pos);
set_fs(oldfs);
if (len <= 0) {
if (len < 0)
errno = len;
else
errno = 0;
break;
}
/* BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_INITEXIT, MP_INIT,
* DBG_LVL_ALL, buff,
* MAX_TRANSFER_CTRL_BYTE_USB);
*/
errno = InterfaceWRM(psIntfAdapter, on_chip_loc, buff, len);
if (errno)
break;
on_chip_loc += MAX_TRANSFER_CTRL_BYTE_USB;
}
kfree(buff);
return errno;
}
int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp,
unsigned int on_chip_loc)
{
char *buff, *buff_readback;
unsigned int reg = 0;
mm_segment_t oldfs = {0};
int errno = 0, len = 0, is_config_file = 0;
loff_t pos = 0;
static int fw_down;
INT Status = STATUS_SUCCESS;
struct bcm_interface_adapter *psIntfAdapter = arg;
int bytes;
buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA);
buff_readback = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
if (!buff || !buff_readback) {
kfree(buff);
kfree(buff_readback);
return -ENOMEM;
}
is_config_file = (on_chip_loc == CONFIG_BEGIN_ADDR) ? 1 : 0;
while (1) {
oldfs = get_fs();
set_fs(get_ds());
len = vfs_read(flp, (void __force __user *)buff,
MAX_TRANSFER_CTRL_BYTE_USB, &pos);
set_fs(oldfs);
fw_down++;
if (len <= 0) {
if (len < 0)
errno = len;
else
errno = 0;
break;
}
bytes = InterfaceRDM(psIntfAdapter, on_chip_loc,
buff_readback, len);
if (bytes < 0) {
Status = bytes;
goto exit;
}
reg++;
if ((len-sizeof(unsigned int)) < 4) {
if (memcmp(buff_readback, buff, len)) {
Status = -EIO;
goto exit;
}
} else {
len -= 4;
while (len) {
if (*(unsigned int *)&buff_readback[len] !=
*(unsigned int *)&buff[len]) {
Status = -EIO;
goto exit;
}
len -= 4;
}
}
on_chip_loc += MAX_TRANSFER_CTRL_BYTE_USB;
} /* End of while(1) */
exit:
kfree(buff);
kfree(buff_readback);
return Status;
}
static int bcm_download_config_file(struct bcm_mini_adapter *Adapter,
struct bcm_firmware_info *psFwInfo)
{
int retval = STATUS_SUCCESS;
B_UINT32 value = 0;
if (Adapter->pstargetparams == NULL) {
Adapter->pstargetparams =
kmalloc(sizeof(struct bcm_target_params), GFP_KERNEL);
if (Adapter->pstargetparams == NULL)
return -ENOMEM;
}
if (psFwInfo->u32FirmwareLength != sizeof(struct bcm_target_params))
return -EIO;
retval = copy_from_user(Adapter->pstargetparams,
psFwInfo->pvMappedFirmwareAddress,
psFwInfo->u32FirmwareLength);
if (retval) {
kfree(Adapter->pstargetparams);
Adapter->pstargetparams = NULL;
return -EFAULT;
}
/* Parse the structure and then Download the Firmware */
beceem_parse_target_struct(Adapter);
/* Initializing the NVM. */
BcmInitNVM(Adapter);
retval = InitLedSettings(Adapter);
if (retval)
return retval;
if (Adapter->LEDInfo.led_thread_running &
BCM_LED_THREAD_RUNNING_ACTIVELY) {
Adapter->LEDInfo.bLedInitDone = false;
Adapter->DriverState = DRIVER_INIT;
wake_up(&Adapter->LEDInfo.notify_led_event);
}
if (Adapter->LEDInfo.led_thread_running &
BCM_LED_THREAD_RUNNING_ACTIVELY) {
Adapter->DriverState = FW_DOWNLOAD;
wake_up(&Adapter->LEDInfo.notify_led_event);
}
/* Initialize the DDR Controller */
retval = ddr_init(Adapter);
if (retval)
return retval;
value = 0;
wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4,
&value, sizeof(value));
wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8,
&value, sizeof(value));
if (Adapter->eNVMType == NVM_FLASH) {
retval = PropagateCalParamsFromFlashToMemory(Adapter);
if (retval)
return retval;
}
retval = buffDnldVerify(Adapter, (PUCHAR)Adapter->pstargetparams,
sizeof(struct bcm_target_params), CONFIG_BEGIN_ADDR);
if (retval)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT,
MP_INIT, DBG_LVL_ALL,
"configuration file not downloaded properly");
else
Adapter->bCfgDownloaded = TRUE;
return retval;
}
int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter,
struct bcm_firmware_info *psFwInfo)
{
int retval = STATUS_SUCCESS;
PUCHAR buff = NULL;
/* Config File is needed for the Driver to download the Config file and
* Firmware. Check for the Config file to be first to be sent from the
* Application
*/
atomic_set(&Adapter->uiMBupdate, false);
if (!Adapter->bCfgDownloaded &&
psFwInfo->u32StartingAddress != CONFIG_BEGIN_ADDR) {
/* Can't Download Firmware. */
return -EINVAL;
}
/* If Config File, Finish the DDR Settings and then Download CFG File */
if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) {
retval = bcm_download_config_file(Adapter, psFwInfo);
} else {
buff = kzalloc(psFwInfo->u32FirmwareLength, GFP_KERNEL);
if (buff == NULL)
return -ENOMEM;
retval = copy_from_user(buff,
psFwInfo->pvMappedFirmwareAddress,
psFwInfo->u32FirmwareLength);
if (retval != STATUS_SUCCESS) {
retval = -EFAULT;
goto error;
}
retval = buffDnldVerify(Adapter,
buff,
psFwInfo->u32FirmwareLength,
psFwInfo->u32StartingAddress);
if (retval != STATUS_SUCCESS)
goto error;
}
error:
kfree(buff);
return retval;
}
static INT buffDnld(struct bcm_mini_adapter *Adapter,
PUCHAR mappedbuffer, UINT u32FirmwareLength,
ULONG u32StartingAddress)
{
unsigned int len = 0;
int retval = STATUS_SUCCESS;
len = u32FirmwareLength;
while (u32FirmwareLength) {
len = MIN_VAL(u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
retval = wrm(Adapter, u32StartingAddress, mappedbuffer, len);
if (retval)
break;
u32StartingAddress += len;
u32FirmwareLength -= len;
mappedbuffer += len;
}
return retval;
}
static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter,
PUCHAR mappedbuffer, UINT u32FirmwareLength,
ULONG u32StartingAddress)
{
UINT len = u32FirmwareLength;
INT retval = STATUS_SUCCESS;
PUCHAR readbackbuff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
int bytes;
if (NULL == readbackbuff)
return -ENOMEM;
while (u32FirmwareLength && !retval) {
len = MIN_VAL(u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
bytes = rdm(Adapter, u32StartingAddress, readbackbuff, len);
if (bytes < 0) {
retval = bytes;
break;
}
if (memcmp(readbackbuff, mappedbuffer, len) != 0) {
pr_err("%s() failed. The firmware doesn't match what was written",
__func__);
retval = -EIO;
}
u32StartingAddress += len;
u32FirmwareLength -= len;
mappedbuffer += len;
} /* end of while (u32FirmwareLength && !retval) */
kfree(readbackbuff);
return retval;
}
INT buffDnldVerify(struct bcm_mini_adapter *Adapter,
unsigned char *mappedbuffer,
unsigned int u32FirmwareLength,
unsigned long u32StartingAddress)
{
INT status = STATUS_SUCCESS;
status = buffDnld(Adapter, mappedbuffer,
u32FirmwareLength, u32StartingAddress);
if (status != STATUS_SUCCESS)
goto error;
status = buffRdbkVerify(Adapter, mappedbuffer,
u32FirmwareLength, u32StartingAddress);
if (status != STATUS_SUCCESS)
goto error;
error:
return status;
}

View File

@ -1,274 +0,0 @@
#include "headers.h"
/*
Function: InterfaceIdleModeWakeup
Description: This is the hardware specific Function for
waking up HW device from Idle mode.
A software abort pattern is written to the
device to wake it and necessary power state
transitions from host are performed here.
Input parameters: IN struct bcm_mini_adapter *Adapter
- Miniport Adapter Context
Return: BCM_STATUS_SUCCESS - If Wakeup of the HW Interface
was successful.
Other - If an error occurred.
*/
/*
Function: InterfaceIdleModeRespond
Description: This is the hardware specific Function for
responding to Idle mode request from target.
Necessary power state transitions from host for
idle mode or other device specific initializations
are performed here.
Input parameters: IN struct bcm_mini_adapter * Adapter
- Miniport Adapter Context
Return: BCM_STATUS_SUCCESS - If Idle mode response related
HW configuration was successful.
Other - If an error occurred.
*/
/*
"dmem bfc02f00 100" tells how many time device went in Idle mode.
this value will be at address bfc02fa4.just before value d0ea1dle.
Set time value by writing at bfc02f98 7d0
checking the Ack timer expire on kannon by running command
d qcslog .. if it shows e means host has not send response
to f/w with in 200 ms. Response should be
send to f/w with in 200 ms after the Idle/Shutdown req issued
*/
int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter,
unsigned int *puiBuffer)
{
int status = STATUS_SUCCESS;
unsigned int uiRegRead = 0;
int bytes;
if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) {
if (ntohl(*(puiBuffer+1)) == 0) {
status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
&uiRegRead, sizeof(uiRegRead));
if (status)
return status;
if (Adapter->ulPowerSaveMode ==
DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
uiRegRead = 0x00000000;
status = wrmalt(Adapter,
DEBUG_INTERRUPT_GENERATOR_REGISTOR,
&uiRegRead, sizeof(uiRegRead));
if (status)
return status;
}
/* Below Register should not br read in case of
* Manual and Protocol Idle mode */
else if (Adapter->ulPowerSaveMode !=
DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
/* clear on read Register */
bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0,
&uiRegRead, sizeof(uiRegRead));
if (bytes < 0) {
status = bytes;
return status;
}
/* clear on read Register */
bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1,
&uiRegRead, sizeof(uiRegRead));
if (bytes < 0) {
status = bytes;
return status;
}
}
/* Set Idle Mode Flag to False and
* Clear IdleMode reg. */
Adapter->IdleMode = false;
Adapter->bTriedToWakeUpFromlowPowerMode = false;
wake_up(&Adapter->lowpower_mode_wait_queue);
} else {
if (TRUE == Adapter->IdleMode)
return status;
uiRegRead = 0;
if (Adapter->chip_id == BCS220_2 ||
Adapter->chip_id == BCS220_2BC ||
Adapter->chip_id == BCS250_BC ||
Adapter->chip_id == BCS220_3) {
bytes = rdmalt(Adapter, HPM_CONFIG_MSW,
&uiRegRead, sizeof(uiRegRead));
if (bytes < 0) {
status = bytes;
return status;
}
uiRegRead |= (1<<17);
status = wrmalt(Adapter, HPM_CONFIG_MSW,
&uiRegRead, sizeof(uiRegRead));
if (status)
return status;
}
SendIdleModeResponse(Adapter);
}
} else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) {
OverrideServiceFlowParams(Adapter, puiBuffer);
}
return status;
}
static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter,
unsigned int Pattern)
{
int status = STATUS_SUCCESS;
unsigned int value;
unsigned int chip_id;
unsigned long timeout = 0, itr = 0;
int lenwritten = 0;
unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
struct bcm_interface_adapter *psInterfaceAdapter =
Adapter->pvInterfaceAdapter;
/* Abort Bus suspend if its already suspended */
if ((TRUE == psInterfaceAdapter->bSuspended) &&
(TRUE == Adapter->bDoSuspend))
status = usb_autopm_get_interface(
psInterfaceAdapter->interface);
if ((Adapter->ulPowerSaveMode ==
DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) ||
(Adapter->ulPowerSaveMode ==
DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) {
/* write the SW abort pattern. */
status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
&Pattern, sizeof(Pattern));
if (status)
return status;
}
if (Adapter->ulPowerSaveMode ==
DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
value = 0x80000000;
status = wrmalt(Adapter,
DEBUG_INTERRUPT_GENERATOR_REGISTOR,
&value, sizeof(value));
if (status)
return status;
} else if (Adapter->ulPowerSaveMode !=
DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
/*
* Get a Interrupt Out URB and send 8 Bytes Down
* To be Done in Thread Context.
* Not using Asynchronous Mechanism.
*/
status = usb_interrupt_msg(psInterfaceAdapter->udev,
usb_sndintpipe(psInterfaceAdapter->udev,
psInterfaceAdapter->sIntrOut.int_out_endpointAddr),
aucAbortPattern,
8,
&lenwritten,
5000);
if (status)
return status;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
IDLE_MODE, DBG_LVL_ALL,
"NOB Sent down :%d", lenwritten);
/* mdelay(25); */
timeout = jiffies + msecs_to_jiffies(50);
while (time_after(timeout, jiffies)) {
itr++;
rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT));
if (0xbece3200 == (chip_id&~(0xF0)))
chip_id = chip_id&~(0xF0);
if (chip_id == Adapter->chip_id)
break;
}
if (time_before(timeout, jiffies))
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
IDLE_MODE, DBG_LVL_ALL,
"Not able to read chip-id even after 25 msec");
else
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
IDLE_MODE, DBG_LVL_ALL,
"Number of completed iteration to read chip-id :%lu", itr);
status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
&Pattern, sizeof(status));
if (status)
return status;
}
return status;
}
int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
{
if (Adapter->bTriedToWakeUpFromlowPowerMode) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
IDLE_MODE, DBG_LVL_ALL,
"Wake up already attempted.. ignoring\n");
} else {
Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern);
}
return 0;
}
void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
{
unsigned int uiRegVal = 0;
INT Status = 0;
int bytes;
if (Adapter->ulPowerSaveMode ==
DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
/* clear idlemode interrupt. */
uiRegVal = 0;
Status = wrmalt(Adapter,
DEBUG_INTERRUPT_GENERATOR_REGISTOR,
&uiRegVal, sizeof(uiRegVal));
if (Status)
return;
}
else {
/* clear Interrupt EP registers. */
bytes = rdmalt(Adapter,
DEVICE_INT_OUT_EP_REG0,
&uiRegVal, sizeof(uiRegVal));
if (bytes < 0) {
Status = bytes;
return;
}
bytes = rdmalt(Adapter,
DEVICE_INT_OUT_EP_REG1,
&uiRegVal, sizeof(uiRegVal));
if (bytes < 0) {
Status = bytes;
return;
}
}
}

View File

@ -1,15 +0,0 @@
#ifndef _INTERFACE_IDLEMODE_H
#define _INTERFACE_IDLEMODE_H
INT InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter);
INT InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter,
unsigned int *puiBuffer);
VOID InterfaceWriteIdleModeWakePattern(struct bcm_mini_adapter *Adapter);
INT InterfaceWakeUp(struct bcm_mini_adapter *Adapter);
VOID InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter);
#endif

View File

@ -1,729 +0,0 @@
#include "headers.h"
#include <linux/usb/ch9.h>
static struct usb_device_id InterfaceUsbtable[] = {
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SYM) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_326) },
{ }
};
MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
static int debug = -1;
module_param(debug, uint, 0600);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static const u32 default_msg =
NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
static int InterfaceAdapterInit(struct bcm_interface_adapter *Adapter);
static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter)
{
int i = 0;
struct bcm_mini_adapter *ps_ad = psIntfAdapter->psAdapter;
/* Wake up the wait_queue... */
if (ps_ad->LEDInfo.led_thread_running &
BCM_LED_THREAD_RUNNING_ACTIVELY) {
ps_ad->DriverState = DRIVER_HALT;
wake_up(&ps_ad->LEDInfo.notify_led_event);
}
reset_card_proc(ps_ad);
/*
* worst case time taken by the RDM/WRM will be 5 sec. will check after
* every 100 ms to accertain the device is not being accessed. After
* this No RDM/WRM should be made.
*/
while (ps_ad->DeviceAccess) {
BCM_DEBUG_PRINT(ps_ad, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL, "Device is being accessed.\n");
msleep(100);
}
/* Free interrupt URB */
/* ps_ad->device_removed = TRUE; */
usb_free_urb(psIntfAdapter->psInterruptUrb);
/* Free transmit URBs */
for (i = 0; i < MAXIMUM_USB_TCB; i++) {
if (psIntfAdapter->asUsbTcb[i].urb != NULL) {
usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
psIntfAdapter->asUsbTcb[i].urb = NULL;
}
}
/* Free receive URB and buffers */
for (i = 0; i < MAXIMUM_USB_RCB; i++) {
if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
psIntfAdapter->asUsbRcb[i].urb = NULL;
}
}
AdapterFree(ps_ad);
}
static void ConfigureEndPointTypesThroughEEPROM(
struct bcm_mini_adapter *Adapter)
{
u32 ulReg;
int bytes;
struct bcm_interface_adapter *interfaceAdapter;
/* Program EP2 MAX_PKT_SIZE */
ulReg = ntohl(EP2_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
ulReg = ntohl(EP2_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
ulReg = ntohl(EP2_CFG_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
interfaceAdapter =
(struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter);
if (interfaceAdapter->bHighSpeedDevice) {
ulReg = ntohl(EP2_CFG_INT);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
} else {
/* USE BULK EP as TX in FS mode. */
ulReg = ntohl(EP2_CFG_BULK);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
}
/* Program EP4 MAX_PKT_SIZE. */
ulReg = ntohl(EP4_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
ulReg = ntohl(EP4_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
/* Program TX EP as interrupt(Alternate Setting) */
bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32));
if (bytes < 0) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL, "reading of Tx EP failed\n");
return;
}
ulReg |= 0x6;
ulReg = ntohl(ulReg);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
ulReg = ntohl(EP4_CFG_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
/* Program ISOCHRONOUS EP size to zero. */
ulReg = ntohl(ISO_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
ulReg = ntohl(ISO_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
/*
* Update EEPROM Version.
* Read 4 bytes from 508 and modify 511 and 510.
*/
ReadBeceemEEPROM(Adapter, 0x1FC, &ulReg);
ulReg &= 0x0101FFFF;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
/*
* Update length field if required.
* Also make the string NULL terminated.
*/
ReadBeceemEEPROM(Adapter, 0xA8, &ulReg);
if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
}
ReadBeceemEEPROM(Adapter, 0x148, &ulReg);
if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
}
ulReg = 0;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
ulReg = 0;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
}
static int usbbcm_device_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
int retval;
struct bcm_mini_adapter *psAdapter;
struct bcm_interface_adapter *psIntfAdapter;
struct net_device *ndev;
/* Reserve one extra queue for the bit-bucket */
ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter),
NO_OF_QUEUES + 1);
if (ndev == NULL) {
dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &intf->dev);
psAdapter = netdev_priv(ndev);
psAdapter->dev = ndev;
psAdapter->msg_enable = netif_msg_init(debug, default_msg);
/* Init default driver debug state */
psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
/*
* Technically, one can start using BCM_DEBUG_PRINT after this point.
* However, realize that by default the Type/Subtype bitmaps are all
* zero now; so no prints will actually appear until the TestApp turns
* on debug paths via the ioctl(); so practically speaking, in early
* init, no logging happens.
*
* A solution (used below): we explicitly set the bitmaps to 1 for
* Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm
* debug statements get logged, enabling debug during early init.
* Further, we turn this OFF once init_module() completes.
*/
psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
BCM_SHOW_DEBUG_BITMAP(psAdapter);
retval = InitAdapter(psAdapter);
if (retval) {
dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
AdapterFree(psAdapter);
return retval;
}
/* Allocate interface adapter structure */
psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter),
GFP_KERNEL);
if (psIntfAdapter == NULL) {
AdapterFree(psAdapter);
return -ENOMEM;
}
psAdapter->pvInterfaceAdapter = psIntfAdapter;
psIntfAdapter->psAdapter = psAdapter;
/* Store usb interface in Interface Adapter */
psIntfAdapter->interface = intf;
usb_set_intfdata(intf, psIntfAdapter);
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"psIntfAdapter 0x%p\n", psIntfAdapter);
retval = InterfaceAdapterInit(psIntfAdapter);
if (retval) {
/* If the Firmware/Cfg File is not present
* then return success, let the application
* download the files.
*/
if (-ENOENT == retval) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"File Not Found. Use app to download.\n");
return STATUS_SUCCESS;
}
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL, "InterfaceAdapterInit failed.\n");
usb_set_intfdata(intf, NULL);
udev = interface_to_usbdev(intf);
usb_put_dev(udev);
InterfaceAdapterFree(psIntfAdapter);
return retval;
}
if (psAdapter->chip_id > T3) {
uint32_t uiNackZeroLengthInt = 4;
retval =
wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT,
&uiNackZeroLengthInt,
sizeof(uiNackZeroLengthInt));
if (retval)
return retval;
}
/* Check whether the USB-Device Supports remote Wake-Up */
if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
/* If Suspend then only support dynamic suspend */
if (psAdapter->bDoSuspend) {
#ifdef CONFIG_PM
pm_runtime_set_autosuspend_delay(&udev->dev, 0);
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(udev);
device_init_wakeup(&intf->dev, 1);
INIT_WORK(&psIntfAdapter->usbSuspendWork,
putUsbSuspend);
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Enabling USB Auto-Suspend\n");
#endif
} else {
intf->needs_remote_wakeup = 0;
usb_disable_autosuspend(udev);
}
}
psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
return retval;
}
static void usbbcm_disconnect(struct usb_interface *intf)
{
struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
struct bcm_mini_adapter *psAdapter;
struct usb_device *udev = interface_to_usbdev(intf);
if (psIntfAdapter == NULL)
return;
psAdapter = psIntfAdapter->psAdapter;
netif_device_detach(psAdapter->dev);
if (psAdapter->bDoSuspend)
intf->needs_remote_wakeup = 0;
psAdapter->device_removed = TRUE;
usb_set_intfdata(intf, NULL);
InterfaceAdapterFree(psIntfAdapter);
usb_put_dev(udev);
}
static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter)
{
int i = 0;
for (i = 0; i < MAXIMUM_USB_TCB; i++) {
psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbTcb[i].urb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Tx urb for index %d\n",
i);
return -ENOMEM;
}
}
for (i = 0; i < MAXIMUM_USB_RCB; i++) {
psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Rx urb for index %d\n",
i);
return -ENOMEM;
}
psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Rx buffer for index %d\n",
i);
return -ENOMEM;
}
psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length =
MAX_DATA_BUFFER_SIZE;
}
return 0;
}
static int device_run(struct bcm_interface_adapter *psIntfAdapter)
{
int value = 0;
UINT status = STATUS_SUCCESS;
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
status = InitCardAndDownloadFirmware(psAd);
if (status != STATUS_SUCCESS) {
pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
return status;
}
if (psAd->fw_download_done) {
if (StartInterruptUrb(psIntfAdapter)) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Cannot send interrupt in URB\n");
}
/*
* now register the cntrl interface. after downloading the f/w
* waiting for 5 sec to get the mailbox interrupt.
*/
psAd->waiting_to_fw_download_done = false;
value = wait_event_timeout(psAd->ioctl_fw_dnld_wait_queue,
psAd->waiting_to_fw_download_done,
5 * HZ);
if (value == 0)
pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
if (register_control_device_interface(psAd) < 0) {
pr_err(DRV_NAME ": Register Control Device failed.\n");
return -EIO;
}
}
return 0;
}
static int select_alternate_setting_for_highspeed_modem(
struct bcm_interface_adapter *psIntfAdapter,
struct usb_endpoint_descriptor **endpoint,
const struct usb_host_interface *iface_desc,
int *usedIntOutForBulkTransfer)
{
int retval = 0;
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
/* selecting alternate setting one as a default setting
* for High Speed modem. */
if (psIntfAdapter->bHighSpeedDevice)
retval = usb_set_interface(psIntfAdapter->udev,
DEFAULT_SETTING_0,
ALTERNATE_SETTING_1);
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"BCM16 is applicable on this dongle\n");
if (retval || !psIntfAdapter->bHighSpeedDevice) {
*usedIntOutForBulkTransfer = EP2;
*endpoint = &iface_desc->endpoint[EP2].desc;
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
/*
* If Modem is high speed device EP2 should be
* INT OUT End point
*
* If Mode is FS then EP2 should be bulk end
* point
*/
if ((psIntfAdapter->bHighSpeedDevice &&
!usb_endpoint_is_int_out(*endpoint)) ||
(!psIntfAdapter->bHighSpeedDevice &&
!usb_endpoint_is_bulk_out(*endpoint))) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Configuring the EEPROM\n");
/* change the EP2, EP4 to INT OUT end point */
ConfigureEndPointTypesThroughEEPROM(
psAd);
/*
* It resets the device and if any thing
* gets changed in USB descriptor it
* will show fail and re-enumerate the
* device
*/
retval = usb_reset_device(psIntfAdapter->udev);
if (retval) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
DRV_ENTRY, DBG_LVL_ALL,
"reset failed. Re-enumerating the device.\n");
return retval;
}
}
if (!psIntfAdapter->bHighSpeedDevice &&
usb_endpoint_is_bulk_out(*endpoint)) {
/*
* Once BULK is selected in FS mode.
* Revert it back to INT.
* Else USB_IF will fail.
*/
UINT _uiData = ntohl(EP2_CFG_INT);
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Reverting Bulk to INT as it is in Full Speed mode.\n");
BeceemEEPROMBulkWrite(psAd, (PUCHAR) & _uiData, 0x136,
4, TRUE);
}
} else {
*usedIntOutForBulkTransfer = EP4;
*endpoint = &iface_desc->endpoint[EP4].desc;
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Choosing AltSetting as a default setting.\n");
if (!usb_endpoint_is_int_out(*endpoint)) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Dongle does not have BCM16 Fix.\n");
/*
* change the EP2, EP4 to INT OUT end point and use EP4
* in altsetting
*/
ConfigureEndPointTypesThroughEEPROM(psAd);
/*
* It resets the device and if any thing
* gets changed in USB descriptor it
* will show fail and re-enumerate the
* device
*/
retval = usb_reset_device(psIntfAdapter->udev);
if (retval) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
DRV_ENTRY, DBG_LVL_ALL,
"reset failed. Re-enumerating the device.\n");
return retval;
}
}
}
return 0;
}
static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
unsigned long value;
int retval = 0;
int usedIntOutForBulkTransfer = 0;
bool bBcm16 = false;
UINT uiData = 0;
int bytes;
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
/* Store the usb dev into interface adapter */
psIntfAdapter->udev =
usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
psIntfAdapter->bHighSpeedDevice =
(psIntfAdapter->udev->speed == USB_SPEED_HIGH);
psAd->interface_rdm = BcmRDM;
psAd->interface_wrm = BcmWRM;
bytes = rdmalt(psAd, CHIP_ID_REG, (u32 *) &(psAd->chip_id),
sizeof(u32));
if (bytes < 0) {
retval = bytes;
BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
"CHIP ID Read Failed\n");
return retval;
}
if (0xbece3200 == (psAd->chip_id & ~(0xF0)))
psAd->chip_id &= ~0xF0;
dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
psAd->chip_id);
iface_desc = psIntfAdapter->interface->cur_altsetting;
if (psAd->chip_id == T3B) {
/* T3B device will have EEPROM, check if EEPROM is proper and
* BCM16 can be done or not. */
BeceemEEPROMBulkRead(psAd, &uiData, 0x0, 4);
if (uiData == BECM)
bBcm16 = TRUE;
dev_info(&psIntfAdapter->udev->dev,
"number of alternate setting %d\n",
psIntfAdapter->interface->num_altsetting);
if (bBcm16 == TRUE) {
retval = select_alternate_setting_for_highspeed_modem(
psIntfAdapter, &endpoint, iface_desc,
&usedIntOutForBulkTransfer);
if (retval)
return retval;
}
}
iface_desc = psIntfAdapter->interface->cur_altsetting;
for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
endpoint = &iface_desc->endpoint[value].desc;
if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr &&
usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
psIntfAdapter->sBulkIn.bulk_in_endpointAddr =
endpoint->bEndpointAddress;
psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe(
psIntfAdapter->udev,
psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
}
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
usb_endpoint_is_bulk_out(endpoint)) {
psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
endpoint->bEndpointAddress;
psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe(
psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
}
if (!psIntfAdapter->sIntrIn.int_in_endpointAddr &&
usb_endpoint_is_int_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sIntrIn.int_in_size = buffer_size;
psIntfAdapter->sIntrIn.int_in_endpointAddr =
endpoint->bEndpointAddress;
psIntfAdapter->sIntrIn.int_in_interval =
endpoint->bInterval;
psIntfAdapter->sIntrIn.int_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrIn.int_in_buffer)
return -EINVAL;
}
if (!psIntfAdapter->sIntrOut.int_out_endpointAddr &&
usb_endpoint_is_int_out(endpoint)) {
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
(psAd->chip_id == T3B) &&
(value == usedIntOutForBulkTransfer)) {
/*
* use first intout end point as a bulk out end
* point
*/
buffer_size =
le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sBulkOut.bulk_out_size =
buffer_size;
psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
endpoint->bEndpointAddress;
psIntfAdapter->sBulkOut.bulk_out_pipe =
usb_sndintpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkOut
.bulk_out_endpointAddr);
psIntfAdapter->sBulkOut.int_out_interval =
endpoint->bInterval;
} else if (value == EP6) {
buffer_size =
le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sIntrOut.int_out_size =
buffer_size;
psIntfAdapter->sIntrOut.int_out_endpointAddr =
endpoint->bEndpointAddress;
psIntfAdapter->sIntrOut.int_out_interval =
endpoint->bInterval;
psIntfAdapter->sIntrOut.int_out_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrOut.int_out_buffer)
return -EINVAL;
}
}
}
usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
psAd->bcm_file_download = InterfaceFileDownload;
psAd->bcm_file_readback_from_chip = InterfaceFileReadbackFromChip;
psAd->interface_transmit = InterfaceTransmitPacket;
retval = CreateInterruptUrb(psIntfAdapter);
if (retval) {
BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
"Cannot create interrupt urb\n");
return retval;
}
retval = AllocUsbCb(psIntfAdapter);
if (retval)
return retval;
return device_run(psIntfAdapter);
}
static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
{
struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
psIntfAdapter->bSuspended = TRUE;
if (psIntfAdapter->bPreparingForBusSuspend) {
psIntfAdapter->bPreparingForBusSuspend = false;
if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
psIntfAdapter->psAdapter->IdleMode = TRUE;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Host Entered in PMU Idle Mode.\n");
} else {
psIntfAdapter->psAdapter->bShutStatus = TRUE;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_INITEXIT, DRV_ENTRY,
DBG_LVL_ALL,
"Host Entered in PMU Shutdown Mode.\n");
}
}
psIntfAdapter->psAdapter->bPreparingForLowPowerMode = false;
/* Signaling the control pkt path */
wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
return 0;
}
static int InterfaceResume(struct usb_interface *intf)
{
struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
mdelay(100);
psIntfAdapter->bSuspended = false;
StartInterruptUrb(psIntfAdapter);
InterfaceRx(psIntfAdapter);
return 0;
}
static struct usb_driver usbbcm_driver = {
.name = "usbbcm",
.probe = usbbcm_device_probe,
.disconnect = usbbcm_disconnect,
.suspend = InterfaceSuspend,
.resume = InterfaceResume,
.id_table = InterfaceUsbtable,
.supports_autosuspend = 1,
};
struct class *bcm_class;
static __init int bcm_init(void)
{
int retval;
pr_info("%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
pr_info("%s\n", DRV_COPYRIGHT);
bcm_class = class_create(THIS_MODULE, DRV_NAME);
if (IS_ERR(bcm_class)) {
pr_err(DRV_NAME ": could not create class\n");
return PTR_ERR(bcm_class);
}
retval = usb_register(&usbbcm_driver);
if (retval < 0) {
pr_err(DRV_NAME ": could not register usb driver\n");
class_destroy(bcm_class);
return retval;
}
return 0;
}
static __exit void bcm_exit(void)
{
usb_deregister(&usbbcm_driver);
class_destroy(bcm_class);
}
module_init(bcm_init);
module_exit(bcm_exit);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");

View File

@ -1,26 +0,0 @@
#ifndef _INTERFACE_INIT_H
#define _INTERFACE_INIT_H
#define BCM_USB_VENDOR_ID_T3 0x198f
#define BCM_USB_VENDOR_ID_FOXCONN 0x0489
#define BCM_USB_VENDOR_ID_ZTE 0x19d2
#define BCM_USB_PRODUCT_ID_T3 0x0300
#define BCM_USB_PRODUCT_ID_T3B 0x0210
#define BCM_USB_PRODUCT_ID_T3L 0x0220
#define BCM_USB_PRODUCT_ID_SYM 0x15E
#define BCM_USB_PRODUCT_ID_1901 0xe017
#define BCM_USB_PRODUCT_ID_226 0x0132 /* not sure if this is valid */
#define BCM_USB_PRODUCT_ID_ZTE_226 0x172
#define BCM_USB_PRODUCT_ID_ZTE_326 0x173 /* ZTE AX326 */
#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007
#define BCM_USB_MINOR_BASE 192
int InterfaceInitialize(void);
int InterfaceExit(void);
int usbbcm_worker_thread(struct bcm_interface_adapter *psIntfAdapter);
#endif

View File

@ -1,190 +0,0 @@
#include "headers.h"
static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
int status = urb->status;
struct bcm_interface_adapter *psIntfAdapter =
(struct bcm_interface_adapter *)urb->context;
struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
if (netif_msg_intr(Adapter))
pr_info(PFX "%s: interrupt status %d\n",
Adapter->dev->name, status);
if (Adapter->device_removed) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Device has Got Removed.");
return;
}
if ((Adapter->bPreparingForLowPowerMode && Adapter->bDoSuspend) ||
psIntfAdapter->bSuspended ||
psIntfAdapter->bPreparingForBusSuspend) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Interrupt call back is called while suspending the device");
return;
}
switch (status) {
/* success */
case STATUS_SUCCESS:
if (urb->actual_length) {
if (psIntfAdapter->ulInterruptData[1] & 0xFF) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"Got USIM interrupt");
}
if (psIntfAdapter->ulInterruptData[1] & 0xFF00) {
atomic_set(&Adapter->CurrNumFreeTxDesc,
(psIntfAdapter->ulInterruptData[1] &
0xFF00) >> 8);
atomic_set(&Adapter->uiMBupdate, TRUE);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"TX mailbox contains %d",
atomic_read(&Adapter->CurrNumFreeTxDesc));
}
if (psIntfAdapter->ulInterruptData[1] >> 16) {
Adapter->CurrNumRecvDescs =
(psIntfAdapter->ulInterruptData[1] >> 16);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"RX mailbox contains %d",
Adapter->CurrNumRecvDescs);
InterfaceRx(psIntfAdapter);
}
if (Adapter->fw_download_done &&
!Adapter->downloadDDR &&
atomic_read(&Adapter->CurrNumFreeTxDesc)) {
psIntfAdapter->psAdapter->downloadDDR += 1;
wake_up(&Adapter->tx_packet_wait_queue);
}
if (!Adapter->waiting_to_fw_download_done) {
Adapter->waiting_to_fw_download_done = TRUE;
wake_up(&Adapter->ioctl_fw_dnld_wait_queue);
}
if (!atomic_read(&Adapter->TxPktAvail)) {
atomic_set(&Adapter->TxPktAvail, 1);
wake_up(&Adapter->tx_packet_wait_queue);
}
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Firing interrupt in URB");
}
break;
case -ENOENT:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "URB has got disconnected....");
return;
case -EINPROGRESS:
/*
* This situation may happened when URBunlink is used. for
* detail check usb_unlink_urb documentation.
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Impossibe condition has occurred... something very bad is going on");
break;
/* return; */
case -EPIPE:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Interrupt IN endPoint has got halted/stalled...need to clear this");
Adapter->bEndPointHalted = TRUE;
wake_up(&Adapter->tx_packet_wait_queue);
urb->status = STATUS_SUCCESS;
return;
/* software-driven interface shutdown */
case -ECONNRESET: /* URB got unlinked */
case -ESHUTDOWN: /* hardware gone. this is the serious problem */
/*
* Occurs only when something happens with the
* host controller device
*/
case -ENODEV: /* Device got removed */
case -EINVAL:
/*
* Some thing very bad happened with the URB. No
* description is available.
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "interrupt urb error %d", status);
urb->status = STATUS_SUCCESS;
break;
/* return; */
default:
/*
* This is required to check what is the defaults conditions
* when it occurs..
*/
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
"GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...",
status);
break;
}
StartInterruptUrb(psIntfAdapter);
}
int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
psIntfAdapter->psInterruptUrb = usb_alloc_urb(0, GFP_KERNEL);
if (!psIntfAdapter->psInterruptUrb) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS,
INTF_INIT, DBG_LVL_ALL,
"Cannot allocate interrupt urb");
return -ENOMEM;
}
psIntfAdapter->psInterruptUrb->transfer_buffer =
psIntfAdapter->ulInterruptData;
psIntfAdapter->psInterruptUrb->transfer_buffer_length =
sizeof(psIntfAdapter->ulInterruptData);
psIntfAdapter->sIntrIn.int_in_pipe = usb_rcvintpipe(psIntfAdapter->udev,
psIntfAdapter->sIntrIn.int_in_endpointAddr);
usb_fill_int_urb(psIntfAdapter->psInterruptUrb, psIntfAdapter->udev,
psIntfAdapter->sIntrIn.int_in_pipe,
psIntfAdapter->psInterruptUrb->transfer_buffer,
psIntfAdapter->psInterruptUrb->transfer_buffer_length,
read_int_callback, psIntfAdapter,
psIntfAdapter->sIntrIn.int_in_interval);
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL, "Interrupt Interval: %d\n",
psIntfAdapter->sIntrIn.int_in_interval);
return 0;
}
INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
INT status = 0;
if (!(psIntfAdapter->psAdapter->device_removed ||
psIntfAdapter->psAdapter->bEndPointHalted ||
psIntfAdapter->bSuspended ||
psIntfAdapter->bPreparingForBusSuspend ||
psIntfAdapter->psAdapter->StopAllXaction)) {
status =
usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC);
if (status) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,
"Cannot send inturb %d\n", status);
if (status == -EPIPE) {
psIntfAdapter->psAdapter->bEndPointHalted =
TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
}
}
}
return status;
}

View File

@ -1,15 +0,0 @@
#ifndef _INTERFACE_ISR_H
#define _INTERFACE_ISR_H
int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter);
INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter);
VOID InterfaceEnableInterrupt(struct bcm_mini_adapter *Adapter);
VOID InterfaceDisableInterrupt(struct bcm_mini_adapter *Adapter);
#endif

View File

@ -1,18 +0,0 @@
#ifndef _INTERFACE_MACROS_H
#define _INTERFACE_MACROS_H
#define BCM_USB_MAX_READ_LENGTH 2048
#define MAXIMUM_USB_TCB 128
#define MAXIMUM_USB_RCB 128
#define MAX_BUFFERS_PER_QUEUE 256
#define MAX_DATA_BUFFER_SIZE 2048
/* Num of Asynchronous reads pending */
#define NUM_RX_DESC 64
#define SYS_CFG 0x0F000C00
#endif

View File

@ -1,247 +0,0 @@
#include "headers.h"
static int adapter_err_occurred(const struct bcm_interface_adapter *ad)
{
if (ad->psAdapter->device_removed == TRUE) {
BCM_DEBUG_PRINT(ad->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Device got removed");
return -ENODEV;
}
if ((ad->psAdapter->StopAllXaction == TRUE) &&
(ad->psAdapter->chip_id >= T3LPB)) {
BCM_DEBUG_PRINT(ad->psAdapter, DBG_TYPE_OTHERS, RDM,
DBG_LVL_ALL,
"Currently Xaction is not allowed on the bus");
return -EACCES;
}
if (ad->bSuspended == TRUE || ad->bPreparingForBusSuspend == TRUE) {
BCM_DEBUG_PRINT(ad->psAdapter, DBG_TYPE_OTHERS, RDM,
DBG_LVL_ALL,
"Bus is in suspended states hence RDM not allowed..");
return -EACCES;
}
return 0;
}
int InterfaceRDM(struct bcm_interface_adapter *psIntfAdapter,
unsigned int addr,
void *buff,
int len)
{
int bytes;
int err = 0;
if (!psIntfAdapter)
return -EINVAL;
err = adapter_err_occurred(psIntfAdapter);
if (err)
return err;
psIntfAdapter->psAdapter->DeviceAccess = TRUE;
bytes = usb_control_msg(psIntfAdapter->udev,
usb_rcvctrlpipe(psIntfAdapter->udev, 0),
0x02,
0xC2,
(addr & 0xFFFF),
((addr >> 16) & 0xFFFF),
buff,
len,
5000);
if (-ENODEV == bytes)
psIntfAdapter->psAdapter->device_removed = TRUE;
if (bytes < 0)
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM,
DBG_LVL_ALL, "RDM failed status :%d", bytes);
else
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM,
DBG_LVL_ALL, "RDM sent %d", bytes);
psIntfAdapter->psAdapter->DeviceAccess = false;
return bytes;
}
int InterfaceWRM(struct bcm_interface_adapter *psIntfAdapter,
unsigned int addr,
void *buff,
int len)
{
int retval = 0;
int err = 0;
if (!psIntfAdapter)
return -EINVAL;
err = adapter_err_occurred(psIntfAdapter);
if (err)
return err;
psIntfAdapter->psAdapter->DeviceAccess = TRUE;
retval = usb_control_msg(psIntfAdapter->udev,
usb_sndctrlpipe(psIntfAdapter->udev, 0),
0x01,
0x42,
(addr & 0xFFFF),
((addr >> 16) & 0xFFFF),
buff,
len,
5000);
if (-ENODEV == retval)
psIntfAdapter->psAdapter->device_removed = TRUE;
if (retval < 0) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM,
DBG_LVL_ALL, "WRM failed status :%d", retval);
psIntfAdapter->psAdapter->DeviceAccess = false;
return retval;
} else {
psIntfAdapter->psAdapter->DeviceAccess = false;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM,
DBG_LVL_ALL, "WRM sent %d", retval);
return STATUS_SUCCESS;
}
}
int BcmRDM(void *arg,
unsigned int addr,
void *buff,
int len)
{
return InterfaceRDM((struct bcm_interface_adapter *)arg, addr, buff,
len);
}
int BcmWRM(void *arg,
unsigned int addr,
void *buff,
int len)
{
return InterfaceWRM((struct bcm_interface_adapter *)arg, addr, buff,
len);
}
int Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter)
{
struct bcm_interface_adapter *psIntfAdapter =
(struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter);
int status = STATUS_SUCCESS;
/*
* usb_clear_halt - tells device to clear endpoint halt/stall condition
* @dev: device whose endpoint is halted
* @pipe: endpoint "pipe" being cleared
* @ Context: !in_interrupt ()
*
* usb_clear_halt is the synchrnous call and returns 0 on success else
* returns with error code.
* This is used to clear halt conditions for bulk and interrupt
* endpoints only.
* Control and isochronous endpoints never halts.
*
* Any URBs queued for such an endpoint should normally be unlinked by
* the driver before clearing the halt condition.
*
*/
/* Killing all the submitted urbs to different end points. */
Bcm_kill_all_URBs(psIntfAdapter);
/* clear the halted/stalled state for every end point */
status = usb_clear_halt(psIntfAdapter->udev,
psIntfAdapter->sIntrIn.int_in_pipe);
if (status != STATUS_SUCCESS)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Unable to Clear Halt of Interrupt IN end point. :%d ",
status);
status = usb_clear_halt(psIntfAdapter->udev,
psIntfAdapter->sBulkIn.bulk_in_pipe);
if (status != STATUS_SUCCESS)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Unable to Clear Halt of Bulk IN end point. :%d ",
status);
status = usb_clear_halt(psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_pipe);
if (status != STATUS_SUCCESS)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
DBG_LVL_ALL,
"Unable to Clear Halt of Bulk OUT end point. :%d ",
status);
return status;
}
void Bcm_kill_all_URBs(struct bcm_interface_adapter *psIntfAdapter)
{
struct urb *tempUrb = NULL;
unsigned int i;
/*
* usb_kill_urb - cancel a transfer request and wait for it to finish
* @urb: pointer to URB describing a previously submitted request,
* returns nothing as it is void returned API.
*
* This routine cancels an in-progress request. It is guaranteed that
* upon return all completion handlers will have finished and the URB
* will be totally idle and available for reuse
*
* This routine may not be used in an interrupt context (such as a
* bottom half or a completion handler), or when holding a spinlock, or
* in other situations where the caller can't schedule().
*
*/
/* Cancel submitted Interrupt-URB's */
if (psIntfAdapter->psInterruptUrb) {
if (psIntfAdapter->psInterruptUrb->status == -EINPROGRESS)
usb_kill_urb(psIntfAdapter->psInterruptUrb);
}
/* Cancel All submitted TX URB's */
for (i = 0; i < MAXIMUM_USB_TCB; i++) {
tempUrb = psIntfAdapter->asUsbTcb[i].urb;
if (tempUrb) {
if (tempUrb->status == -EINPROGRESS)
usb_kill_urb(tempUrb);
}
}
for (i = 0; i < MAXIMUM_USB_RCB; i++) {
tempUrb = psIntfAdapter->asUsbRcb[i].urb;
if (tempUrb) {
if (tempUrb->status == -EINPROGRESS)
usb_kill_urb(tempUrb);
}
}
atomic_set(&psIntfAdapter->uNumTcbUsed, 0);
atomic_set(&psIntfAdapter->uCurrTcb, 0);
atomic_set(&psIntfAdapter->uNumRcbUsed, 0);
atomic_set(&psIntfAdapter->uCurrRcb, 0);
}
void putUsbSuspend(struct work_struct *work)
{
struct bcm_interface_adapter *psIntfAdapter = NULL;
struct usb_interface *intf = NULL;
psIntfAdapter = container_of(work, struct bcm_interface_adapter,
usbSuspendWork);
intf = psIntfAdapter->interface;
if (psIntfAdapter->bSuspended == false)
usb_autopm_put_interface(intf);
}

View File

@ -1,42 +0,0 @@
#ifndef __INTERFACE_MISC_H
#define __INTERFACE_MISC_H
INT
InterfaceRDM(struct bcm_interface_adapter *psIntfAdapter,
UINT addr,
PVOID buff,
INT len);
INT
InterfaceWRM(struct bcm_interface_adapter *psIntfAdapter,
UINT addr,
PVOID buff,
INT len);
int InterfaceFileDownload(PVOID psIntfAdapter,
struct file *flp,
unsigned int on_chip_loc);
int InterfaceFileReadbackFromChip(PVOID psIntfAdapter,
struct file *flp,
unsigned int on_chip_loc);
int BcmRDM(PVOID arg,
UINT addr,
PVOID buff,
INT len);
int BcmWRM(PVOID arg,
UINT addr,
PVOID buff,
INT len);
INT Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter);
VOID Bcm_kill_all_URBs(struct bcm_interface_adapter *psIntfAdapter);
#define DISABLE_USB_ZERO_LEN_INT 0x0F011878
#endif /* __INTERFACE_MISC_H */

View File

@ -1,289 +0,0 @@
#include "headers.h"
static void handle_control_packet(struct bcm_interface_adapter *interface,
struct bcm_mini_adapter *ad,
struct bcm_leader *leader,
struct sk_buff *skb,
struct urb *urb)
{
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL,
"Received control pkt...");
*(PUSHORT)skb->data = leader->Status;
memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
(sizeof(struct bcm_leader)), leader->PLength);
skb->len = leader->PLength + sizeof(USHORT);
spin_lock(&ad->control_queue_lock);
ENQUEUEPACKET(ad->RxControlHead, ad->RxControlTail, skb);
spin_unlock(&ad->control_queue_lock);
atomic_inc(&ad->cntrlpktCnt);
wake_up(&ad->process_rx_cntrlpkt);
}
static void format_eth_hdr_to_stack(struct bcm_interface_adapter *interface,
struct bcm_mini_adapter *ad,
struct bcm_leader *p_leader,
struct sk_buff *skb,
struct urb *urb,
UINT ui_index,
int queue_index,
bool b_header_supression_endabled)
{
/*
* Data Packet, Format a proper Ethernet Header
* and give it to the stack
*/
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX, RX_DATA,
DBG_LVL_ALL, "Received Data pkt...");
skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES);
memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer +
sizeof(struct bcm_leader), p_leader->PLength);
skb->dev = ad->dev;
/* currently skb->len has extra ETH_HLEN bytes in the beginning */
skb_put(skb, p_leader->PLength + ETH_HLEN);
ad->PackInfo[queue_index].uiTotalRxBytes += p_leader->PLength;
ad->PackInfo[queue_index].uiThisPeriodRxBytes += p_leader->PLength;
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX, RX_DATA,
DBG_LVL_ALL, "Received Data pkt of len :0x%X",
p_leader->PLength);
if (netif_running(ad->dev)) {
/* Moving ahead by ETH_HLEN to the data ptr as received from FW */
skb_pull(skb, ETH_HLEN);
PHSReceive(ad, p_leader->Vcid, skb, &skb->len,
NULL, b_header_supression_endabled);
if (!ad->PackInfo[queue_index].bEthCSSupport) {
skb_push(skb, ETH_HLEN);
memcpy(skb->data, skb->dev->dev_addr, 6);
memcpy(skb->data+6, skb->dev->dev_addr, 6);
(*(skb->data+11))++;
*(skb->data+12) = 0x08;
*(skb->data+13) = 0x00;
p_leader->PLength += ETH_HLEN;
}
skb->protocol = eth_type_trans(skb, ad->dev);
netif_rx(skb);
} else {
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX,
RX_DATA, DBG_LVL_ALL,
"i/f not up hance freeing SKB...");
dev_kfree_skb(skb);
}
++ad->dev->stats.rx_packets;
ad->dev->stats.rx_bytes += p_leader->PLength;
for (ui_index = 0; ui_index < MIBS_MAX_HIST_ENTRIES; ui_index++) {
if ((p_leader->PLength <=
MIBS_PKTSIZEHIST_RANGE*(ui_index+1)) &&
(p_leader->PLength > MIBS_PKTSIZEHIST_RANGE*(ui_index)))
ad->aRxPktSizeHist[ui_index]++;
}
}
static int SearchVcid(struct bcm_mini_adapter *Adapter, unsigned short usVcid)
{
int iIndex = 0;
for (iIndex = (NO_OF_QUEUES-1); iIndex >= 0; iIndex--)
if (Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
return iIndex;
return NO_OF_QUEUES+1;
}
static struct bcm_usb_rcb *
GetBulkInRcb(struct bcm_interface_adapter *psIntfAdapter)
{
struct bcm_usb_rcb *pRcb = NULL;
UINT index = 0;
if ((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) &&
(psIntfAdapter->psAdapter->StopAllXaction == false)) {
index = atomic_read(&psIntfAdapter->uCurrRcb);
pRcb = &psIntfAdapter->asUsbRcb[index];
pRcb->bUsed = TRUE;
pRcb->psIntfAdapter = psIntfAdapter;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC,
DBG_LVL_ALL, "Got Rx desc %d used %d", index,
atomic_read(&psIntfAdapter->uNumRcbUsed));
index = (index + 1) % MAXIMUM_USB_RCB;
atomic_set(&psIntfAdapter->uCurrRcb, index);
atomic_inc(&psIntfAdapter->uNumRcbUsed);
}
return pRcb;
}
/*this is receive call back - when pkt available for receive (BULK IN- end point)*/
static void read_bulk_callback(struct urb *urb)
{
struct sk_buff *skb = NULL;
bool bHeaderSupressionEnabled = false;
int QueueIndex = NO_OF_QUEUES + 1;
UINT uiIndex = 0;
struct bcm_usb_rcb *pRcb = (struct bcm_usb_rcb *)urb->context;
struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter;
struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
struct bcm_leader *pLeader = urb->transfer_buffer;
if (unlikely(netif_msg_rx_status(Adapter)))
pr_info(PFX "%s: rx urb status %d length %d\n",
Adapter->dev->name, urb->status, urb->actual_length);
if ((Adapter->device_removed == TRUE) ||
(TRUE == Adapter->bEndPointHalted) ||
(0 == urb->actual_length)) {
pRcb->bUsed = false;
atomic_dec(&psIntfAdapter->uNumRcbUsed);
return;
}
if (urb->status != STATUS_SUCCESS) {
if (urb->status == -EPIPE) {
Adapter->bEndPointHalted = TRUE;
wake_up(&Adapter->tx_packet_wait_queue);
} else {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC,
DBG_LVL_ALL,
"Rx URB has got cancelled. status :%d",
urb->status);
}
pRcb->bUsed = false;
atomic_dec(&psIntfAdapter->uNumRcbUsed);
urb->status = STATUS_SUCCESS;
return;
}
if (Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
"device is going in low power mode while PMU option selected..hence rx packet should not be process");
return;
}
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
"Read back done len %d\n", pLeader->PLength);
if (!pLeader->PLength) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
"Leader Length 0");
atomic_dec(&psIntfAdapter->uNumRcbUsed);
return;
}
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
"Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX",
pLeader->Status, pLeader->PLength, pLeader->Vcid);
if (MAX_CNTL_PKT_SIZE < pLeader->PLength) {
if (netif_msg_rx_err(Adapter))
pr_info(PFX "%s: corrupted leader length...%d\n",
Adapter->dev->name, pLeader->PLength);
++Adapter->dev->stats.rx_dropped;
atomic_dec(&psIntfAdapter->uNumRcbUsed);
return;
}
QueueIndex = SearchVcid(Adapter, pLeader->Vcid);
if (QueueIndex < NO_OF_QUEUES) {
bHeaderSupressionEnabled =
Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
bHeaderSupressionEnabled =
bHeaderSupressionEnabled & Adapter->bPHSEnabled;
}
skb = dev_alloc_skb(pLeader->PLength + SKB_RESERVE_PHS_BYTES +
SKB_RESERVE_ETHERNET_HEADER);
if (!skb) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
"NO SKBUFF!!! Dropping the Packet");
atomic_dec(&psIntfAdapter->uNumRcbUsed);
return;
}
/* If it is a control Packet, then call handle_bcm_packet ()*/
if ((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) ||
(!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) {
handle_control_packet(psIntfAdapter, Adapter, pLeader, skb,
urb);
} else {
format_eth_hdr_to_stack(psIntfAdapter, Adapter, pLeader, skb,
urb, uiIndex, QueueIndex,
bHeaderSupressionEnabled);
}
Adapter->PrevNumRecvDescs++;
pRcb->bUsed = false;
atomic_dec(&psIntfAdapter->uNumRcbUsed);
}
static int ReceiveRcb(struct bcm_interface_adapter *psIntfAdapter,
struct bcm_usb_rcb *pRcb)
{
struct urb *urb = pRcb->urb;
int retval = 0;
usb_fill_bulk_urb(urb, psIntfAdapter->udev,
usb_rcvbulkpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkIn.bulk_in_endpointAddr),
urb->transfer_buffer,
BCM_USB_MAX_READ_LENGTH,
read_bulk_callback, pRcb);
if (false == psIntfAdapter->psAdapter->device_removed &&
false == psIntfAdapter->psAdapter->bEndPointHalted &&
false == psIntfAdapter->bSuspended &&
false == psIntfAdapter->bPreparingForBusSuspend) {
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX,
RX_DPC, DBG_LVL_ALL,
"failed submitting read urb, error %d",
retval);
/* if this return value is because of pipe halt. need to clear this. */
if (retval == -EPIPE) {
psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
}
}
}
return retval;
}
/*
Function: InterfaceRx
Description: This is the hardware specific Function for Receiving
data packet/control packets from the device.
Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context
Return: TRUE - If Rx was successful.
Other - If an error occurred.
*/
bool InterfaceRx(struct bcm_interface_adapter *psIntfAdapter)
{
USHORT RxDescCount = NUM_RX_DESC -
atomic_read(&psIntfAdapter->uNumRcbUsed);
struct bcm_usb_rcb *pRcb = NULL;
while (RxDescCount) {
pRcb = GetBulkInRcb(psIntfAdapter);
if (pRcb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
DBG_TYPE_PRINTK, 0, 0,
"Unable to get Rcb pointer");
return false;
}
ReceiveRcb(psIntfAdapter, pRcb);
RxDescCount--;
}
return TRUE;
}

View File

@ -1,7 +0,0 @@
#ifndef _INTERFACE_RX_H
#define _INTERFACE_RX_H
bool InterfaceRx(struct bcm_interface_adapter *Adapter);
#endif

View File

@ -1,213 +0,0 @@
#include "headers.h"
static void prepare_low_power_mode(struct urb *urb,
struct bcm_interface_adapter *interface,
struct bcm_mini_adapter *ps_adapter,
struct bcm_mini_adapter *ad,
struct bcm_link_request *p_control_msg,
bool *b_power_down_msg)
{
if (((p_control_msg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) &&
(p_control_msg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE))) {
*b_power_down_msg = TRUE;
/*
* This covers the bus err while Idle Request msg
* sent down.
*/
if (urb->status != STATUS_SUCCESS) {
ps_adapter->bPreparingForLowPowerMode = false;
BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL,
"Idle Mode Request msg failed to reach to Modem");
/* Signalling the cntrl pkt path in Ioctl */
wake_up(&ps_adapter->lowpower_mode_wait_queue);
StartInterruptUrb(interface);
return;
}
if (ps_adapter->bDoSuspend == false) {
ps_adapter->IdleMode = TRUE;
/* since going in Idle mode completed hence making this var false */
ps_adapter->bPreparingForLowPowerMode = false;
BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL,
"Host Entered in Idle Mode State...");
/* Signalling the cntrl pkt path in Ioctl*/
wake_up(&ps_adapter->lowpower_mode_wait_queue);
}
} else if ((p_control_msg->Leader.Status == LINK_UP_CONTROL_REQ) &&
(p_control_msg->szData[0] == LINK_UP_ACK) &&
(p_control_msg->szData[1] == LINK_SHUTDOWN_REQ_FROM_FIRMWARE) &&
(p_control_msg->szData[2] == SHUTDOWN_ACK_FROM_DRIVER)) {
/*
* This covers the bus err while shutdown Request
* msg sent down.
*/
if (urb->status != STATUS_SUCCESS) {
ps_adapter->bPreparingForLowPowerMode = false;
BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL,
"Shutdown Request Msg failed to reach to Modem");
/* Signalling the cntrl pkt path in Ioctl */
wake_up(&ps_adapter->lowpower_mode_wait_queue);
StartInterruptUrb(interface);
return;
}
*b_power_down_msg = TRUE;
if (ps_adapter->bDoSuspend == false) {
ps_adapter->bShutStatus = TRUE;
/*
* since going in shutdown mode completed hence
* making this var false
*/
ps_adapter->bPreparingForLowPowerMode = false;
BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL,
"Host Entered in shutdown Mode State...");
/* Signalling the cntrl pkt path in Ioctl */
wake_up(&ps_adapter->lowpower_mode_wait_queue);
}
}
if (ps_adapter->bDoSuspend && *b_power_down_msg) {
/* issuing bus suspend request */
BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
"Issuing the Bus suspend request to USB stack");
interface->bPreparingForBusSuspend = TRUE;
schedule_work(&interface->usbSuspendWork);
}
}
/*this is transmit call-back(BULK OUT)*/
static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
struct bcm_usb_tcb *pTcb = (struct bcm_usb_tcb *)urb->context;
struct bcm_interface_adapter *psIntfAdapter = pTcb->psIntfAdapter;
struct bcm_link_request *pControlMsg =
(struct bcm_link_request *)urb->transfer_buffer;
struct bcm_mini_adapter *psAdapter = psIntfAdapter->psAdapter;
bool bpowerDownMsg = false;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
if (unlikely(netif_msg_tx_done(Adapter)))
pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name,
urb->status);
if (urb->status != STATUS_SUCCESS) {
if (urb->status == -EPIPE) {
psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
} else {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL,
"Tx URB has got cancelled. status :%d",
urb->status);
}
}
pTcb->bUsed = false;
atomic_dec(&psIntfAdapter->uNumTcbUsed);
if (TRUE == psAdapter->bPreparingForLowPowerMode) {
prepare_low_power_mode(urb, psIntfAdapter, psAdapter, Adapter,
pControlMsg, &bpowerDownMsg);
}
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
}
static struct bcm_usb_tcb *GetBulkOutTcb(struct bcm_interface_adapter *psIntfAdapter)
{
struct bcm_usb_tcb *pTcb = NULL;
UINT index = 0;
if ((atomic_read(&psIntfAdapter->uNumTcbUsed) < MAXIMUM_USB_TCB) &&
(psIntfAdapter->psAdapter->StopAllXaction == false)) {
index = atomic_read(&psIntfAdapter->uCurrTcb);
pTcb = &psIntfAdapter->asUsbTcb[index];
pTcb->bUsed = TRUE;
pTcb->psIntfAdapter = psIntfAdapter;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX,
NEXT_SEND, DBG_LVL_ALL,
"Got Tx desc %d used %d",
index,
atomic_read(&psIntfAdapter->uNumTcbUsed));
index = (index + 1) % MAXIMUM_USB_TCB;
atomic_set(&psIntfAdapter->uCurrTcb, index);
atomic_inc(&psIntfAdapter->uNumTcbUsed);
}
return pTcb;
}
static int TransmitTcb(struct bcm_interface_adapter *psIntfAdapter,
struct bcm_usb_tcb *pTcb, PVOID data, int len)
{
struct urb *urb = pTcb->urb;
int retval = 0;
urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len,
GFP_ATOMIC, &urb->transfer_dma);
if (!urb->transfer_buffer) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Error allocating memory\n");
return -ENOMEM;
}
memcpy(urb->transfer_buffer, data, len);
urb->transfer_buffer_length = len;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, NEXT_SEND,
DBG_LVL_ALL, "Sending Bulk out packet\n");
/* For T3B,INT OUT end point will be used as bulk out end point */
if ((psIntfAdapter->psAdapter->chip_id == T3B) &&
(psIntfAdapter->bHighSpeedDevice == TRUE)) {
usb_fill_int_urb(urb, psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_pipe,
urb->transfer_buffer, len, write_bulk_callback, pTcb,
psIntfAdapter->sBulkOut.int_out_interval);
} else {
usb_fill_bulk_urb(urb, psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_pipe,
urb->transfer_buffer, len, write_bulk_callback, pTcb);
}
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* For DMA transfer */
if (false == psIntfAdapter->psAdapter->device_removed &&
false == psIntfAdapter->psAdapter->bEndPointHalted &&
false == psIntfAdapter->bSuspended &&
false == psIntfAdapter->bPreparingForBusSuspend) {
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX,
NEXT_SEND, DBG_LVL_ALL,
"failed submitting write urb, error %d",
retval);
if (retval == -EPIPE) {
psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
}
}
}
return retval;
}
int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len)
{
struct bcm_usb_tcb *pTcb = NULL;
struct bcm_interface_adapter *psIntfAdapter = arg;
pTcb = GetBulkOutTcb(psIntfAdapter);
if (pTcb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"No URB to transmit packet, dropping packet");
return -EFAULT;
}
return TransmitTcb(psIntfAdapter, pTcb, data, len);
}

View File

@ -1,7 +0,0 @@
#ifndef _INTERFACE_TX_H
#define _INTERFACE_TX_H
INT InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len);
#endif

View File

@ -1,226 +0,0 @@
#ifndef _IOCTL_H_
#define _IOCTL_H_
struct bcm_rdm_buffer {
unsigned long Register;
unsigned long Length;
} __packed;
struct bcm_wrm_buffer {
unsigned long Register;
unsigned long Length;
unsigned char Data[4];
} __packed;
struct bcm_ioctl_buffer {
void __user *InputBuffer;
unsigned long InputLength;
void __user *OutputBuffer;
unsigned long OutputLength;
} __packed;
struct bcm_gpio_info {
unsigned int uiGpioNumber; /* valid numbers 0-15 */
unsigned int uiGpioValue; /* 1 set ; 0 not set */
} __packed;
struct bcm_user_thread_req {
/* 0->Inactivate LED thread. */
/* 1->Activate the LED thread */
unsigned int ThreadState;
} __packed;
#define LED_THREAD_ACTIVATION_REQ 1
#define BCM_IOCTL 'k'
#define IOCTL_SEND_CONTROL_MESSAGE _IOW(BCM_IOCTL, 0x801, int)
#define IOCTL_BCM_REGISTER_WRITE _IOW(BCM_IOCTL, 0x802, int)
#define IOCTL_BCM_REGISTER_READ _IOR(BCM_IOCTL, 0x803, int)
#define IOCTL_BCM_COMMON_MEMORY_WRITE _IOW(BCM_IOCTL, 0x804, int)
#define IOCTL_BCM_COMMON_MEMORY_READ _IOR(BCM_IOCTL, 0x805, int)
#define IOCTL_GET_CONTROL_MESSAGE _IOR(BCM_IOCTL, 0x806, int)
#define IOCTL_BCM_FIRMWARE_DOWNLOAD _IOW(BCM_IOCTL, 0x807, int)
#define IOCTL_BCM_SET_SEND_VCID _IOW(BCM_IOCTL, 0x808, int)
#define IOCTL_BCM_SWITCH_TRANSFER_MODE _IOW(BCM_IOCTL, 0x809, int)
#define IOCTL_LINK_REQ _IOW(BCM_IOCTL, 0x80A, int)
#define IOCTL_RSSI_LEVEL_REQ _IOW(BCM_IOCTL, 0x80B, int)
#define IOCTL_IDLE_REQ _IOW(BCM_IOCTL, 0x80C, int)
#define IOCTL_SS_INFO_REQ _IOW(BCM_IOCTL, 0x80D, int)
#define IOCTL_GET_STATISTICS_POINTER _IOW(BCM_IOCTL, 0x80E, int)
#define IOCTL_CM_REQUEST _IOW(BCM_IOCTL, 0x80F, int)
#define IOCTL_INIT_PARAM_REQ _IOW(BCM_IOCTL, 0x810, int)
#define IOCTL_MAC_ADDR_REQ _IOW(BCM_IOCTL, 0x811, int)
#define IOCTL_MAC_ADDR_RESP _IOWR(BCM_IOCTL, 0x812, int)
#define IOCTL_CLASSIFICATION_RULE _IOW(BCM_IOCTL, 0x813, char)
#define IOCTL_CLOSE_NOTIFICATION _IO(BCM_IOCTL, 0x814)
#define IOCTL_LINK_UP _IO(BCM_IOCTL, 0x815)
#define IOCTL_LINK_DOWN _IO(BCM_IOCTL, 0x816, struct bcm_ioctl_buffer)
#define IOCTL_CHIP_RESET _IO(BCM_IOCTL, 0x816)
#define IOCTL_CINR_LEVEL_REQ _IOW(BCM_IOCTL, 0x817, char)
#define IOCTL_WTM_CONTROL_REQ _IOW(BCM_IOCTL, 0x817, char)
#define IOCTL_BE_BUCKET_SIZE _IOW(BCM_IOCTL, 0x818, unsigned long)
#define IOCTL_RTPS_BUCKET_SIZE _IOW(BCM_IOCTL, 0x819, unsigned long)
#define IOCTL_QOS_THRESHOLD _IOW(BCM_IOCTL, 0x820, unsigned long)
#define IOCTL_DUMP_PACKET_INFO _IO(BCM_IOCTL, 0x821)
#define IOCTL_GET_PACK_INFO _IOR(BCM_IOCTL, 0x823, int)
#define IOCTL_BCM_GET_DRIVER_VERSION _IOR(BCM_IOCTL, 0x829, int)
#define IOCTL_BCM_GET_CURRENT_STATUS _IOW(BCM_IOCTL, 0x828, int)
#define IOCTL_BCM_GPIO_SET_REQUEST _IOW(BCM_IOCTL, 0x82A, int)
#define IOCTL_BCM_GPIO_STATUS_REQUEST _IOW(BCM_IOCTL, 0x82b, int)
#define IOCTL_BCM_GET_DSX_INDICATION _IOR(BCM_IOCTL, 0x854, int)
#define IOCTL_BCM_BUFFER_DOWNLOAD_START _IOW(BCM_IOCTL, 0x855, int)
#define IOCTL_BCM_BUFFER_DOWNLOAD _IOW(BCM_IOCTL, 0x856, int)
#define IOCTL_BCM_BUFFER_DOWNLOAD_STOP _IOW(BCM_IOCTL, 0x857, int)
#define IOCTL_BCM_REGISTER_WRITE_PRIVATE _IOW(BCM_IOCTL, 0x826, char)
#define IOCTL_BCM_REGISTER_READ_PRIVATE _IOW(BCM_IOCTL, 0x827, char)
#define IOCTL_BCM_SET_DEBUG _IOW(BCM_IOCTL, 0x824, struct bcm_ioctl_buffer)
#define IOCTL_BCM_EEPROM_REGISTER_WRITE _IOW(BCM_IOCTL, 0x858, int)
#define IOCTL_BCM_EEPROM_REGISTER_READ _IOR(BCM_IOCTL, 0x859, int)
#define IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE _IOR(BCM_IOCTL, 0x860, int)
#define IOCTL_BCM_SET_MAC_TRACING _IOW(BCM_IOCTL, 0x82c, int)
#define IOCTL_BCM_GET_HOST_MIBS _IOW(BCM_IOCTL, 0x853, int)
#define IOCTL_BCM_NVM_READ _IOR(BCM_IOCTL, 0x861, int)
#define IOCTL_BCM_NVM_WRITE _IOW(BCM_IOCTL, 0x862, int)
#define IOCTL_BCM_GET_NVM_SIZE _IOR(BCM_IOCTL, 0x863, int)
#define IOCTL_BCM_CAL_INIT _IOR(BCM_IOCTL, 0x864, int)
#define IOCTL_BCM_BULK_WRM _IOW(BCM_IOCTL, 0x90B, int)
#define IOCTL_BCM_FLASH2X_SECTION_READ _IOR(BCM_IOCTL, 0x865, int)
#define IOCTL_BCM_FLASH2X_SECTION_WRITE _IOW(BCM_IOCTL, 0x866, int)
#define IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP _IOR(BCM_IOCTL, 0x867, int)
#define IOCTL_BCM_SET_ACTIVE_SECTION _IOW(BCM_IOCTL, 0x868, int)
#define IOCTL_BCM_IDENTIFY_ACTIVE_SECTION _IO(BCM_IOCTL, 0x869)
#define IOCTL_BCM_COPY_SECTION _IOW(BCM_IOCTL, 0x870, int)
#define IOCTL_BCM_GET_FLASH_CS_INFO _IOR(BCM_IOCTL, 0x871, int)
#define IOCTL_BCM_SELECT_DSD _IOW(BCM_IOCTL, 0x872, int)
#define IOCTL_BCM_NVM_RAW_READ _IOR(BCM_IOCTL, 0x875, int)
#define IOCTL_BCM_CNTRLMSG_MASK _IOW(BCM_IOCTL, 0x874, int)
#define IOCTL_BCM_GET_DEVICE_DRIVER_INFO _IOR(BCM_IOCTL, 0x877, int)
#define IOCTL_BCM_TIME_SINCE_NET_ENTRY _IOR(BCM_IOCTL, 0x876, int)
#define BCM_LED_THREAD_STATE_CHANGE_REQ _IOW(BCM_IOCTL, 0x878, int)
#define IOCTL_BCM_GPIO_MULTI_REQUEST _IOW(BCM_IOCTL, 0x82D, struct bcm_ioctl_buffer)
#define IOCTL_BCM_GPIO_MODE_REQUEST _IOW(BCM_IOCTL, 0x82E, struct bcm_ioctl_buffer)
enum bcm_interface_type {
BCM_MII,
BCM_CARDBUS,
BCM_USB,
BCM_SDIO,
BCM_PCMCIA
};
struct bcm_driver_info {
enum bcm_nvm_type u32NVMType;
unsigned int MaxRDMBufferSize;
enum bcm_interface_type u32InterfaceType;
unsigned int u32DSDStartOffset;
unsigned int u32RxAlignmentCorrection;
unsigned int u32Reserved[10];
};
struct bcm_nvm_readwrite {
void __user *pBuffer;
uint32_t uiOffset;
uint32_t uiNumBytes;
bool bVerify;
};
struct bcm_bulk_wrm_buffer {
unsigned long Register;
unsigned long SwapEndian;
unsigned long Values[1];
};
enum bcm_flash2x_section_val {
NO_SECTION_VAL = 0, /* no section chosen when absolute offset is given for RD/WR */
ISO_IMAGE1,
ISO_IMAGE2,
DSD0,
DSD1,
DSD2,
VSA0,
VSA1,
VSA2,
SCSI,
CONTROL_SECTION,
ISO_IMAGE1_PART2,
ISO_IMAGE1_PART3,
ISO_IMAGE2_PART2,
ISO_IMAGE2_PART3,
TOTAL_SECTIONS
};
/*
* Structure used for READ/WRITE Flash Map2.x
*/
struct bcm_flash2x_readwrite {
enum bcm_flash2x_section_val Section; /* section to be read/written */
u32 offset; /* offset within section. */
u32 numOfBytes; /* number of bytes from the offset */
u32 bVerify;
void __user *pDataBuff; /* buffer for reading/writing */
};
/*
* This structure is used for coping one section to other.
* there are two ways to copy one section to other.
* it NOB =0, complete section will be copied on to other.
* if NOB !=0, only NOB will be copied from the given offset.
*/
struct bcm_flash2x_copy_section {
enum bcm_flash2x_section_val SrcSection;
enum bcm_flash2x_section_val DstSection;
u32 offset;
u32 numOfBytes;
};
/*
* This section provide the complete bitmap of the Flash.
* using this map lib/APP will issue read/write command.
* Fields are defined as :
* Bit [0] = section is present //1:present, 0: Not present
* Bit [1] = section is valid //1: valid, 0: not valid
* Bit [2] = Section is R/W //0: RW, 1: RO
* Bit [3] = Section is Active or not 1 means Active, 0->inactive
* Bit [7...3] = Reserved
*/
struct bcm_flash2x_bitmap {
unsigned char ISO_IMAGE1;
unsigned char ISO_IMAGE2;
unsigned char DSD0;
unsigned char DSD1;
unsigned char DSD2;
unsigned char VSA0;
unsigned char VSA1;
unsigned char VSA2;
unsigned char SCSI;
unsigned char CONTROL_SECTION;
/* Reserved for future use */
unsigned char Reserved0;
unsigned char Reserved1;
unsigned char Reserved2;
};
struct bcm_time_elapsed {
u64 ul64TimeElapsedSinceNetEntry;
u32 uiReserved[4];
};
enum {
WIMAX_IDX = 0, /* To access WiMAX chip GPIO's for GPIO_MULTI_INFO or GPIO_MULTI_MODE */
HOST_IDX, /* To access Host chip GPIO's for GPIO_MULTI_INFO or GPIO_MULTI_MODE */
MAX_IDX
};
struct bcm_gpio_multi_info {
unsigned int uiGPIOCommand; /* 1 for set and 0 for get */
unsigned int uiGPIOMask; /* set the corresponding bit to 1 to access GPIO */
unsigned int uiGPIOValue; /* 0 or 1; value to be set when command is 1. */
} __packed;
struct bcm_gpio_multi_mode {
unsigned int uiGPIOMode; /* 1 for OUT mode, 0 for IN mode */
unsigned int uiGPIOMask; /* GPIO mask to set mode */
} __packed;
#endif

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