Initial Broadcom bcm4329 driver Ver 4.218.97
Dmitry Shmidt [Thu, 16 Jul 2009 23:24:48 +0000 (16:24 -0700)]
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>

109 files changed:
.gitignore [new file with mode: 0644]
bcm4329/Android.mk [new file with mode: 0644]
bcm4329/config/Android.mk [new file with mode: 0644]
bcm4329/config/android_dhcpcd.conf [new file with mode: 0644]
bcm4329/config/wpa_supplicant.conf [new file with mode: 0644]
bcm4329/src/Android.mk [new file with mode: 0644]
bcm4329/src/GNUmakefile.inc [new file with mode: 0644]
bcm4329/src/Makerules [new file with mode: 0644]
bcm4329/src/Makerules.env [new file with mode: 0644]
bcm4329/src/bcmsdio/linux/Makefile [new file with mode: 0644]
bcm4329/src/bcmsdio/linux/makefile.26 [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmpcispi.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdh.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdh_linux.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdspi.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdstd.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c [new file with mode: 0644]
bcm4329/src/bcmsdio/sys/bcmspibrcm.c [new file with mode: 0644]
bcm4329/src/branding.inc [new file with mode: 0644]
bcm4329/src/dhd/exe/GNUmakefile [new file with mode: 0644]
bcm4329/src/dhd/exe/dhdu.c [new file with mode: 0644]
bcm4329/src/dhd/exe/dhdu.h [new file with mode: 0644]
bcm4329/src/dhd/exe/dhdu_cmd.h [new file with mode: 0644]
bcm4329/src/dhd/exe/dhdu_linux.c [new file with mode: 0644]
bcm4329/src/dhd/linux/Makefile [new file with mode: 0644]
bcm4329/src/dhd/linux/makefile.26 [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd.h [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_bus.h [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_cdc.c [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_common.c [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_custom_gpio.c [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_dbg.h [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_linux.c [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_linux_sched.c [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_proto.h [new file with mode: 0644]
bcm4329/src/dhd/sys/dhd_sdio.c [new file with mode: 0644]
bcm4329/src/dongle/dngl_stats.h [new file with mode: 0644]
bcm4329/src/include/Makefile [new file with mode: 0644]
bcm4329/src/include/aidmp.h [new file with mode: 0644]
bcm4329/src/include/bcmcdc.h [new file with mode: 0644]
bcm4329/src/include/bcmdefs.h [new file with mode: 0644]
bcm4329/src/include/bcmdevs.h [new file with mode: 0644]
bcm4329/src/include/bcmendian.h [new file with mode: 0644]
bcm4329/src/include/bcmpcispi.h [new file with mode: 0644]
bcm4329/src/include/bcmperf.h [new file with mode: 0644]
bcm4329/src/include/bcmsdbus.h [new file with mode: 0644]
bcm4329/src/include/bcmsdh.h [new file with mode: 0644]
bcm4329/src/include/bcmsdh_sdmmc.h [new file with mode: 0644]
bcm4329/src/include/bcmsdpcm.h [new file with mode: 0644]
bcm4329/src/include/bcmsdspi.h [new file with mode: 0644]
bcm4329/src/include/bcmsdstd.h [new file with mode: 0644]
bcm4329/src/include/bcmspi.h [new file with mode: 0644]
bcm4329/src/include/bcmspibrcm.h [new file with mode: 0644]
bcm4329/src/include/bcmutils.h [new file with mode: 0644]
bcm4329/src/include/bcmwifi.h [new file with mode: 0644]
bcm4329/src/include/dhdioctl.h [new file with mode: 0644]
bcm4329/src/include/epivers.h [new file with mode: 0644]
bcm4329/src/include/epivers.h.in [new file with mode: 0644]
bcm4329/src/include/epivers.sh [new file with mode: 0644]
bcm4329/src/include/hndpmu.h [new file with mode: 0644]
bcm4329/src/include/hndsoc.h [new file with mode: 0644]
bcm4329/src/include/linux_osl.h [new file with mode: 0644]
bcm4329/src/include/linuxver.h [new file with mode: 0644]
bcm4329/src/include/miniopt.h [new file with mode: 0644]
bcm4329/src/include/msgtrace.h [new file with mode: 0644]
bcm4329/src/include/osl.h [new file with mode: 0644]
bcm4329/src/include/packed_section_end.h [new file with mode: 0644]
bcm4329/src/include/packed_section_start.h [new file with mode: 0644]
bcm4329/src/include/pcicfg.h [new file with mode: 0644]
bcm4329/src/include/proto/802.11.h [new file with mode: 0644]
bcm4329/src/include/proto/802.11e.h [new file with mode: 0644]
bcm4329/src/include/proto/802.1d.h [new file with mode: 0644]
bcm4329/src/include/proto/bcmeth.h [new file with mode: 0644]
bcm4329/src/include/proto/bcmevent.h [new file with mode: 0644]
bcm4329/src/include/proto/bcmip.h [new file with mode: 0644]
bcm4329/src/include/proto/eapol.h [new file with mode: 0644]
bcm4329/src/include/proto/ethernet.h [new file with mode: 0644]
bcm4329/src/include/proto/sdspi.h [new file with mode: 0644]
bcm4329/src/include/proto/vlan.h [new file with mode: 0644]
bcm4329/src/include/proto/wpa.h [new file with mode: 0644]
bcm4329/src/include/sbchipc.h [new file with mode: 0644]
bcm4329/src/include/sbconfig.h [new file with mode: 0644]
bcm4329/src/include/sbhnddma.h [new file with mode: 0644]
bcm4329/src/include/sbpcmcia.h [new file with mode: 0644]
bcm4329/src/include/sbsdio.h [new file with mode: 0644]
bcm4329/src/include/sbsdpcmdev.h [new file with mode: 0644]
bcm4329/src/include/sbsocram.h [new file with mode: 0644]
bcm4329/src/include/sdio.h [new file with mode: 0644]
bcm4329/src/include/sdioh.h [new file with mode: 0644]
bcm4329/src/include/sdiovar.h [new file with mode: 0644]
bcm4329/src/include/siutils.h [new file with mode: 0644]
bcm4329/src/include/spid.h [new file with mode: 0644]
bcm4329/src/include/trxhdr.h [new file with mode: 0644]
bcm4329/src/include/typedefs.h [new file with mode: 0644]
bcm4329/src/include/wlioctl.h [new file with mode: 0644]
bcm4329/src/shared/aiutils.c [new file with mode: 0644]
bcm4329/src/shared/bcmutils.c [new file with mode: 0644]
bcm4329/src/shared/bcmwifi.c [new file with mode: 0644]
bcm4329/src/shared/hndpmu.c [new file with mode: 0644]
bcm4329/src/shared/linux_osl.c [new file with mode: 0644]
bcm4329/src/shared/miniopt.c [new file with mode: 0644]
bcm4329/src/shared/sbutils.c [new file with mode: 0644]
bcm4329/src/shared/siutils.c [new file with mode: 0644]
bcm4329/src/shared/siutils_priv.h [new file with mode: 0644]
bcm4329/src/wl/sys/wl_iw.c [new file with mode: 0644]
bcm4329/src/wl/sys/wl_iw.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..fb72949
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git-ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.ko
+*.so
+*.so.dbg
+*.mod.c
+*.i
+*.lst
+*.symtypes
+*.order
+*.elf
+*.bin
+*.gz
+
+#
+# Top-level generic files
+#
+tags
+TAGS
+Module.markers
+Module.symvers
+!.gitignore
+
+# stgit generated dirs
+patches-*
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+*.orig
+*~
+\#*#
diff --git a/bcm4329/Android.mk b/bcm4329/Android.mk
new file mode 100644 (file)
index 0000000..26a7472
--- /dev/null
@@ -0,0 +1,3 @@
+ifeq ($(BOARD_WLAN_DEVICE),bcm4329)
+    include $(call all-subdir-makefiles)
+endif
diff --git a/bcm4329/config/Android.mk b/bcm4329/config/Android.mk
new file mode 100644 (file)
index 0000000..508a96f
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := wpa_supplicant.conf
+LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dhcpcd.conf
+LOCAL_MODULE_TAGS := user
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/dhcpcd
+LOCAL_SRC_FILES := android_dhcpcd.conf
+include $(BUILD_PREBUILT)
+
+########################
diff --git a/bcm4329/config/android_dhcpcd.conf b/bcm4329/config/android_dhcpcd.conf
new file mode 100644 (file)
index 0000000..35e36cd
--- /dev/null
@@ -0,0 +1,6 @@
+# dhcpcd configuration for Android Wi-Fi interface
+# See dhcpcd.conf(5) for details.
+
+interface eth0
+# dhcpcd-run-hooks uses these options.
+option subnet_mask, routers, domain_name_servers
diff --git a/bcm4329/config/wpa_supplicant.conf b/bcm4329/config/wpa_supplicant.conf
new file mode 100644 (file)
index 0000000..a088262
--- /dev/null
@@ -0,0 +1,747 @@
+##### Example wpa_supplicant configuration file ###############################
+#
+# This file describes configuration file format and lists all available option.
+# Please also take a look at simpler configuration examples in 'examples'
+# subdirectory.
+#
+# Empty lines and lines starting with # are ignored
+
+# NOTE! This file may contain password information and should probably be made
+# readable only by root user on multiuser systems.
+
+# Note: All file paths in this configuration file should use full (absolute,
+# not relative to working directory) path in order to allow working directory
+# to be changed. This can happen if wpa_supplicant is run in the background.
+
+# Whether to allow wpa_supplicant to update (overwrite) configuration
+#
+# This option can be used to allow wpa_supplicant to overwrite configuration
+# file whenever configuration is changed (e.g., new network block is added with
+# wpa_cli or wpa_gui, or a password is changed). This is required for
+# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
+# Please note that overwriting configuration file will remove the comments from
+# it.
+update_config=1
+
+# global configuration (shared by all network blocks)
+#
+# Parameters for the control interface. If this is specified, wpa_supplicant
+# will open a control interface that is available for external programs to
+# manage wpa_supplicant. The meaning of this string depends on which control
+# interface mechanism is used. For all cases, the existance of this parameter
+# in configuration is used to determine whether the control interface is
+# enabled.
+#
+# For UNIX domain sockets (default on Linux and BSD): This is a directory that
+# will be created for UNIX domain sockets for listening to requests from
+# external programs (CLI/GUI, etc.) for status information and configuration.
+# The socket file will be named based on the interface name, so multiple
+# wpa_supplicant processes can be run at the same time if more than one
+# interface is used.
+# /var/run/wpa_supplicant is the recommended directory for sockets and by
+# default, wpa_cli will use it when trying to connect with wpa_supplicant.
+#
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run wpa_supplicant as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
+# want to allow non-root users to use the control interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group. If this variable is commented out or
+# not included in the configuration file, group will not be changed from the
+# value it got by default when the directory or socket was created.
+#
+# When configuring both the directory and group, use following format:
+# DIR=/var/run/wpa_supplicant GROUP=wheel
+# DIR=/var/run/wpa_supplicant GROUP=0
+# (group can be either group name or gid)
+#
+# For UDP connections (default on Windows): The value will be ignored. This
+# variable is just used to select that the control interface is to be created.
+# The value can be set to, e.g., udp (ctrl_interface=udp)
+#
+# For Windows Named Pipe: This value can be used to set the security descriptor
+# for controlling access to the control interface. Security descriptor can be
+# set using Security Descriptor String Format (see http://msdn.microsoft.com/
+# library/default.asp?url=/library/en-us/secauthz/security/
+# security_descriptor_string_format.asp). The descriptor string needs to be
+# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
+# DACL (which will reject all connections). See README-Windows.txt for more
+# information about SDDL string format.
+#
+ctrl_interface=eth0
+
+# IEEE 802.1X/EAPOL version
+# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
+# EAPOL version 2. However, there are many APs that do not handle the new
+# version number correctly (they seem to drop the frames completely). In order
+# to make wpa_supplicant interoperate with these APs, the version number is set
+# to 1 by default. This configuration value can be used to set it to the new
+# version (2).
+eapol_version=1
+
+# AP scanning/selection
+# By default, wpa_supplicant requests driver to perform AP scanning and then
+# uses the scan results to select a suitable AP. Another alternative is to
+# allow the driver to take care of AP scanning and selection and use
+# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association
+# information from the driver.
+# 1: wpa_supplicant initiates scanning and AP selection
+# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
+#    parameters (e.g., WPA IE generation); this mode can also be used with
+#    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
+#    APs (i.e., external program needs to control association). This mode must
+#    also be used when using wired Ethernet drivers.
+# 2: like 0, but associate with APs using security policy and SSID (but not
+#    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
+#    enable operation with hidden SSIDs and optimized roaming; in this mode,
+#    the network blocks in the configuration file are tried one by one until
+#    the driver reports successful association; each network block should have
+#    explicit security policy (i.e., only one option in the lists) for
+#    key_mgmt, pairwise, group, proto variables
+ap_scan=1
+
+# EAP fast re-authentication
+# By default, fast re-authentication is enabled for all EAP methods that
+# support it. This variable can be used to disable fast re-authentication.
+# Normally, there is no need to disable this.
+fast_reauth=1
+
+# OpenSSL Engine support
+# These options can be used to load OpenSSL engines.
+# The two engines that are supported currently are shown below:
+# They are both from the opensc project (http://www.opensc.org/)
+# By default no engines are loaded.
+# make the opensc engine available
+#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
+# make the pkcs11 engine available
+#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
+# configure the path to the pkcs11 module required by the pkcs11 engine
+#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+
+# Dynamic EAP methods
+# If EAP methods were built dynamically as shared object files, they need to be
+# loaded here before being used in the network blocks. By default, EAP methods
+# are included statically in the build, so these lines are not needed
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
+
+# Driver interface parameters
+# This field can be used to configure arbitrary driver interace parameters. The
+# format is specific to the selected driver interface. This field is not used
+# in most cases.
+#driver_param="field=value"
+
+# Maximum lifetime for PMKSA in seconds; default 43200
+#dot11RSNAConfigPMKLifetime=43200
+# Threshold for reauthentication (percentage of PMK lifetime); default 70
+#dot11RSNAConfigPMKReauthThreshold=70
+# Timeout for security association negotiation in seconds; default 60
+#dot11RSNAConfigSATimeout=60
+
+# network block
+#
+# Each network (usually AP's sharing the same SSID) is configured as a separate
+# block in this configuration file. The network blocks are in preference order
+# (the first match is used).
+#
+# network block fields:
+#
+# disabled:
+#      0 = this network can be used (default)
+#      1 = this network block is disabled (can be enabled through ctrl_iface,
+#          e.g., with wpa_cli or wpa_gui)
+#
+# id_str: Network identifier string for external scripts. This value is passed
+#      to external action script through wpa_cli as WPA_ID_STR environment
+#      variable to make it easier to do network specific configuration.
+#
+# ssid: SSID (mandatory); either as an ASCII string with double quotation or
+#      as hex string; network name
+#
+# scan_ssid:
+#      0 = do not scan this SSID with specific Probe Request frames (default)
+#      1 = scan with SSID-specific Probe Request frames (this can be used to
+#          find APs that do not accept broadcast SSID or use multiple SSIDs;
+#          this will add latency to scanning, so enable this only when needed)
+#
+# bssid: BSSID (optional); if set, this network block is used only when
+#      associating with the AP using the configured BSSID
+#
+# priority: priority group (integer)
+# By default, all networks will get same priority group (0). If some of the
+# networks are more desirable, this field can be used to change the order in
+# which wpa_supplicant goes through the networks when selecting a BSS. The
+# priority groups will be iterated in decreasing priority (i.e., the larger the
+# priority value, the sooner the network is matched against the scan results).
+# Within each priority group, networks will be selected based on security
+# policy, signal strength, etc.
+# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
+# using this priority to select the order for scanning. Instead, they try the
+# networks in the order that used in the configuration file.
+#
+# mode: IEEE 802.11 operation mode
+# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
+# 1 = IBSS (ad-hoc, peer-to-peer)
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
+# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In addition, ap_scan has
+# to be set to 2 for IBSS. WPA-None requires following network block options:
+# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
+# both), and psk must also be set.
+#
+# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g.,
+# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial
+# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode.
+# In addition, this value is only used by the station that creates the IBSS. If
+# an IBSS network with the configured SSID is already present, the frequency of
+# the network will be used instead of this configured value.
+#
+# proto: list of accepted protocols
+# WPA = WPA/IEEE 802.11i/D3.0
+# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# If not set, this defaults to: WPA RSN
+#
+# key_mgmt: list of accepted authenticated key management protocols
+# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
+# WPA-EAP = WPA using EAP authentication (this can use an external
+#      program, e.g., Xsupplicant, for IEEE 802.1X EAP Authentication
+# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
+#      generated WEP keys
+# NONE = WPA is not used; plaintext or static WEP could be used
+# If not set, this defaults to: WPA-PSK WPA-EAP
+#
+# auth_alg: list of allowed IEEE 802.11 authentication algorithms
+# OPEN = Open System authentication (required for WPA/WPA2)
+# SHARED = Shared Key authentication (requires static WEP keys)
+# LEAP = LEAP/Network EAP (only used with LEAP)
+# If not set, automatic selection is used (Open System with LEAP enabled if
+# LEAP is allowed as one of the EAP methods).
+#
+# pairwise: list of accepted pairwise (unicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# NONE = Use only Group Keys (deprecated, should not be included if APs support
+#      pairwise keys)
+# If not set, this defaults to: CCMP TKIP
+#
+# group: list of accepted group (broadcast/multicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
+# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
+# If not set, this defaults to: CCMP TKIP WEP104 WEP40
+#
+# psk: WPA preshared key; 256-bit pre-shared key
+# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
+# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
+# generated using the passphrase and SSID). ASCII passphrase must be between
+# 8 and 63 characters (inclusive).
+# This field is not needed, if WPA-EAP is used.
+# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
+# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
+# startup and reconfiguration time can be optimized by generating the PSK only
+# only when the passphrase or SSID has actually changed.
+#
+# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
+# Dynamic WEP key required for non-WPA mode
+# bit0 (1): require dynamically generated unicast WEP key
+# bit1 (2): require dynamically generated broadcast WEP key
+#      (3 = require both keys; default)
+# Note: When using wired authentication, eapol_flags must be set to 0 for the
+# authentication to be completed successfully.
+#
+# mixed_cell: This option can be used to configure whether so called mixed
+# cells, i.e., networks that use both plaintext and encryption in the same
+# SSID, are allowed when selecting a BSS form scan results.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# proactive_key_caching:
+# Enable/disable opportunistic PMKSA caching for WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
+# hex without quotation, e.g., 0102030405)
+# wep_tx_keyidx: Default WEP key index (TX) (0..3)
+#
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+#
+# Following fields are only used with internal EAP implementation.
+# eap: space-separated list of accepted EAP methods
+#      MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+#                      cannot be used with WPA; to be used as a Phase 2 method
+#                      with EAP-PEAP or EAP-TTLS)
+#       MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
+#              as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       OTP = EAP-OTP (cannot be used separately with WPA; to be used
+#              as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       GTC = EAP-GTC (cannot be used separately with WPA; to be used
+#              as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#      TLS = EAP-TLS (client and server certificate)
+#      PEAP = EAP-PEAP (with tunnelled EAP authentication)
+#      TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2
+#                       authentication)
+#      If not set, all compiled in methods are allowed.
+#
+# identity: Identity string for EAP
+# anonymous_identity: Anonymous identity string for EAP (to be used as the
+#      unencrypted identity with EAP types that support different tunnelled
+#      identity, e.g., EAP-TTLS)
+# password: Password string for EAP
+# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
+#      or more trusted CA certificates. If ca_cert and ca_path are not
+#      included, server certificate will not be verified. This is insecure and
+#      a trusted CA certificate should always be configured when using
+#      EAP-TLS/TTLS/PEAP. Full path should be used since working directory may
+#      change when wpa_supplicant is run in the background.
+#      On Windows, trusted CA certificates can be loaded from the system
+#      certificate store by setting this to cert_store://<name>, e.g.,
+#      ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
+#      Note that when running wpa_supplicant as an application, the user
+#      certificate store (My user account) is used, whereas computer store
+#      (Computer account) is used when running wpasvc as a service.
+# ca_path: Directory path for CA certificate files (PEM). This path may
+#      contain multiple CA certificates in OpenSSL format. Common use for this
+#      is to point to system trusted CA list which is often installed into
+#      directory like /etc/ssl/certs. If configured, these certificates are
+#      added to the list of trusted CAs. ca_cert may also be included in that
+#      case, but it is not required.
+# client_cert: File path to client certificate file (PEM/DER)
+#      Full path should be used since working directory may change when
+#      wpa_supplicant is run in the background.
+#      Alternatively, a named configuration blob can be used by setting this
+#      to blob://<blob name>.
+# private_key: File path to client private key file (PEM/DER/PFX)
+#      When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+#      commented out. Both the private key and certificate will be read from
+#      the PKCS#12 file in this case. Full path should be used since working
+#      directory may change when wpa_supplicant is run in the background.
+#      Windows certificate store can be used by leaving client_cert out and
+#      configuring private_key in one of the following formats:
+#      cert://substring_to_match
+#      hash://certificate_thumbprint_in_hex
+#      for example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#      Note that when running wpa_supplicant as an application, the user
+#      certificate store (My user account) is used, whereas computer store
+#      (Computer account) is used when running wpasvc as a service.
+#      Alternatively, a named configuration blob can be used by setting this
+#      to blob://<blob name>.
+# private_key_passwd: Password for private key file (if left out, this will be
+#      asked through control interface)
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+#      This is an optional configuration file for setting parameters for an
+#      ephemeral DH key exchange. In most cases, the default RSA
+#      authentication does not use this configuration. However, it is possible
+#      setup RSA to use ephemeral DH key exchange. In addition, ciphers with
+#      DSA keys always use ephemeral DH keys. This can be used to achieve
+#      forward secrecy. If the file is in DSA parameters format, it will be
+#      automatically converted into DH params.
+# subject_match: Substring to be matched against the subject of the
+#      authentication server certificate. If this string is set, the server
+#      sertificate is only accepted if it contains this string in the subject.
+#      The subject string is in following format:
+#      /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+# altsubject_match: Semicolon separated string of entries to be matched against
+#      the alternative subject name of the authentication server certificate.
+#      If this string is set, the server sertificate is only accepted if it
+#      contains one of the entries in an alternative subject name extension.
+#      altSubjectName string is in following format: TYPE:VALUE
+#      Example: EMAIL:server@example.com
+#      Example: DNS:server.example.com;DNS:server2.example.com
+#      Following types are supported: EMAIL, DNS, URI
+# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
+#      (string with field-value pairs, e.g., "peapver=0" or
+#      "peapver=1 peaplabel=1")
+#      'peapver' can be used to force which PEAP version (0 or 1) is used.
+#      'peaplabel=1' can be used to force new label, "client PEAP encryption",
+#      to be used during key derivation when PEAPv1 or newer. Most existing
+#      PEAPv1 implementation seem to be using the old label, "client EAP
+#      encryption", and wpa_supplicant is now using that as the default value.
+#      Some servers, e.g., Radiator, may require peaplabel=1 configuration to
+#      interoperate with PEAPv1; see eap_testing.txt for more details.
+#      'peap_outer_success=0' can be used to terminate PEAP authentication on
+#      tunneled EAP-Success. This is required with some RADIUS servers that
+#      implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
+#      Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode)
+#      include_tls_length=1 can be used to force wpa_supplicant to include
+#      TLS Message Length field in all TLS messages even if they are not
+#      fragmented.
+#      sim_min_num_chal=3 can be used to configure EAP-SIM to require three
+#      challenges (by default, it accepts 2 or 3)
+# phase2: Phase2 (inner authentication with TLS tunnel) parameters
+#      (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
+#      "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+# Following certificate/private key fields are used in inner Phase2
+# authentication when using EAP-TTLS or EAP-PEAP.
+# ca_cert2: File path to CA certificate file. This file can have one or more
+#      trusted CA certificates. If ca_cert2 and ca_path2 are not included,
+#      server certificate will not be verified. This is insecure and a trusted
+#      CA certificate should always be configured.
+# ca_path2: Directory path for CA certificate files (PEM)
+# client_cert2: File path to client certificate file
+# private_key2: File path to client private key file
+# private_key2_passwd: Password for private key file
+# dh_file2: File path to DH/DSA parameters file (in PEM format)
+# subject_match2: Substring to be matched against the subject of the
+#      authentication server certificate.
+# altsubject_match2: Substring to be matched against the alternative subject
+#      name of the authentication server certificate.
+#
+# fragment_size: Maximum EAP fragment size in bytes (default 1398).
+#      This value limits the fragment size for EAP methods that support
+#      fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
+#      small enough to make the EAP messages fit in MTU of the network
+#      interface used for EAPOL. The default value is suitable for most
+#      cases.
+#
+# EAP-PSK variables:
+# eappsk: 16-byte (128-bit, 32 hex digits) pre-shared key in hex format
+# nai: user NAI
+#
+# EAP-PAX variables:
+# eappsk: 16-byte (128-bit, 32 hex digits) pre-shared key in hex format
+#
+# EAP-SAKE variables:
+# eappsk: 32-byte (256-bit, 64 hex digits) pre-shared key in hex format
+#      (this is concatenation of Root-Secret-A and Root-Secret-B)
+# nai: user NAI (PEERID)
+#
+# EAP-GPSK variables:
+# eappsk: Pre-shared key in hex format (at least 128 bits, i.e., 32 hex digits)
+# nai: user NAI (ID_Client)
+#
+# EAP-FAST variables:
+# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
+#      to create this file and write updates to it when PAC is being
+#      provisioned or refreshed. Full path to the file should be used since
+#      working directory may change when wpa_supplicant is run in the
+#      background. Alternatively, a named configuration blob can be used by
+#      setting this to blob://<blob name>
+# phase1: fast_provisioning=1 option enables in-line provisioning of EAP-FAST
+#      credentials (PAC)
+#
+# wpa_supplicant supports number of "EAP workarounds" to work around
+# interoperability issues with incorrectly behaving authentication servers.
+# These are enabled by default because some of the issues are present in large
+# number of authentication servers. Strict EAP conformance mode can be
+# configured by disabling workarounds with eap_workaround=0.
+
+# Example blocks:
+
+# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
+#network={
+#      ssid="simple"
+#      psk="very secret passphrase"
+#      priority=5
+#}
+
+# Same as previous, but request SSID-specific scanning (for APs that reject
+# broadcast SSID)
+#network={
+#      ssid="second ssid"
+#      scan_ssid=1
+#      psk="very secret passphrase"
+#      priority=2
+#}
+
+# Only WPA-PSK is used. Any valid cipher combination is accepted.
+#network={
+#      ssid="example"
+#      proto=WPA
+#      key_mgmt=WPA-PSK
+#      pairwise=CCMP TKIP
+#      group=CCMP TKIP WEP104 WEP40
+#      psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+#      priority=2
+#}
+
+# Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104
+# or WEP40 as the group cipher will not be accepted.
+#network={
+#      ssid="example"
+#      proto=RSN
+#      key_mgmt=WPA-EAP
+#      pairwise=CCMP TKIP
+#      group=CCMP TKIP
+#      eap=TLS
+#      identity="user@example.com"
+#      ca_cert="/etc/cert/ca.pem"
+#      client_cert="/etc/cert/user.pem"
+#      private_key="/etc/cert/user.prv"
+#      private_key_passwd="password"
+#      priority=1
+#}
+
+# EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel
+# (e.g., Radiator)
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=PEAP
+#      identity="user@example.com"
+#      password="foobar"
+#      ca_cert="/etc/cert/ca.pem"
+#      phase1="peaplabel=1"
+#      phase2="auth=MSCHAPV2"
+#      priority=10
+#}
+
+# EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
+# unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=TTLS
+#      identity="user@example.com"
+#      anonymous_identity="anonymous@example.com"
+#      password="foobar"
+#      ca_cert="/etc/cert/ca.pem"
+#      priority=2
+#}
+
+# EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted
+# use. Real identity is sent only within an encrypted TLS tunnel.
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=TTLS
+#      identity="user@example.com"
+#      anonymous_identity="anonymous@example.com"
+#      password="foobar"
+#      ca_cert="/etc/cert/ca.pem"
+#      phase2="auth=MSCHAPV2"
+#}
+
+# WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner
+# authentication.
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=TTLS
+#      # Phase1 / outer authentication
+#      anonymous_identity="anonymous@example.com"
+#      ca_cert="/etc/cert/ca.pem"
+#      # Phase 2 / inner authentication
+#      phase2="autheap=TLS"
+#      ca_cert2="/etc/cert/ca2.pem"
+#      client_cert2="/etc/cer/user.pem"
+#      private_key2="/etc/cer/user.prv"
+#      private_key2_passwd="password"
+#      priority=2
+#}
+
+# Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
+# group cipher.
+#network={
+#      ssid="example"
+#      bssid=00:11:22:33:44:55
+#      proto=WPA RSN
+#      key_mgmt=WPA-PSK WPA-EAP
+#      pairwise=CCMP
+#      group=CCMP
+#      psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+#}
+
+# Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP
+# and all valid ciphers.
+#network={
+#      ssid=00010203
+#      psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+#}
+
+
+# EAP-SIM with a GSM SIM or USIM
+#network={
+#      ssid="eap-sim-test"
+#      key_mgmt=WPA-EAP
+#      eap=SIM
+#      pin="1234"
+#      pcsc=""
+#}
+
+
+# EAP-PSK
+#network={
+#      ssid="eap-psk-test"
+#      key_mgmt=WPA-EAP
+#      eap=PSK
+#      identity="eap_psk_user"
+#      eappsk=06b4be19da289f475aa46a33cb793029
+#      nai="eap_psk_user@example.com"
+#}
+
+
+# IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using
+# EAP-TLS for authentication and key generation; require both unicast and
+# broadcast WEP keys.
+#network={
+#      ssid="1x-test"
+#      key_mgmt=IEEE8021X
+#      eap=TLS
+#      identity="user@example.com"
+#      ca_cert="/etc/cert/ca.pem"
+#      client_cert="/etc/cert/user.pem"
+#      private_key="/etc/cert/user.prv"
+#      private_key_passwd="password"
+#      eapol_flags=3
+#}
+
+
+# LEAP with dynamic WEP keys
+#network={
+#      ssid="leap-example"
+#      key_mgmt=IEEE8021X
+#      eap=LEAP
+#      identity="user"
+#      password="foobar"
+#}
+
+# EAP-FAST with WPA (WPA or WPA2)
+#network={
+#      ssid="eap-fast-test"
+#      key_mgmt=WPA-EAP
+#      eap=FAST
+#      anonymous_identity="FAST-000102030405"
+#      identity="username"
+#      password="password"
+#      phase1="fast_provisioning=1"
+#      pac_file="/etc/wpa_supplicant.eap-fast-pac"
+#}
+
+#network={
+#      ssid="eap-fast-test"
+#      key_mgmt=WPA-EAP
+#      eap=FAST
+#      anonymous_identity="FAST-000102030405"
+#      identity="username"
+#      password="password"
+#      phase1="fast_provisioning=1"
+#      pac_file="blob://eap-fast-pac"
+#}
+
+# Plaintext connection (no WPA, no IEEE 802.1X)
+#network={
+#      ssid="plaintext-test"
+#      key_mgmt=NONE
+#}
+
+
+# Shared WEP key connection (no WPA, no IEEE 802.1X)
+#network={
+#      ssid="static-wep-test"
+#      key_mgmt=NONE
+#      wep_key0="abcde"
+#      wep_key1=0102030405
+#      wep_key2="1234567890123"
+#      wep_tx_keyidx=0
+#      priority=5
+#}
+
+
+# Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key
+# IEEE 802.11 authentication
+#network={
+#      ssid="static-wep-test2"
+#      key_mgmt=NONE
+#      wep_key0="abcde"
+#      wep_key1=0102030405
+#      wep_key2="1234567890123"
+#      wep_tx_keyidx=0
+#      priority=5
+#      auth_alg=SHARED
+#}
+
+
+# IBSS/ad-hoc network with WPA-None/TKIP.
+#network={
+#      ssid="test adhoc"
+#      mode=1
+#      frequency=2412
+#      proto=WPA
+#      key_mgmt=WPA-NONE
+#      pairwise=NONE
+#      group=TKIP
+#      psk="secret passphrase"
+#}
+
+
+# Catch all example that allows more or less all configuration modes
+#network={
+#      ssid="example"
+#      scan_ssid=1
+#      key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+#      pairwise=CCMP TKIP
+#      group=CCMP TKIP WEP104 WEP40
+#      psk="very secret passphrase"
+#      eap=TTLS PEAP TLS
+#      identity="user@example.com"
+#      password="foobar"
+#      ca_cert="/etc/cert/ca.pem"
+#      client_cert="/etc/cert/user.pem"
+#      private_key="/etc/cert/user.prv"
+#      private_key_passwd="password"
+#      phase1="peaplabel=0"
+#}
+
+# Example of EAP-TLS with smartcard (openssl engine)
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=TLS
+#      proto=RSN
+#      pairwise=CCMP TKIP
+#      group=CCMP TKIP
+#      identity="user@example.com"
+#      ca_cert="/etc/cert/ca.pem"
+#      client_cert="/etc/cert/user.pem"
+#
+#      engine=1
+#
+       # The engine configured here must be available. Look at
+       # OpenSSL engine support in the global section.
+       # The key available through the engine must be the private key
+       # matching the client certificate configured above.
+
+       # use the opensc engine
+       #engine_id="opensc"
+       #key_id="45"
+
+       # use the pkcs11 engine
+#      engine_id="pkcs11"
+#      key_id="id_45"
+
+       # Optional PIN configuration; this can be left out and PIN will be
+       # asked through the control interface
+#      pin="1234"
+#}
+
+# Example configuration showing how to use an inlined blob as a CA certificate
+# data instead of using external file
+#network={
+#      ssid="example"
+#      key_mgmt=WPA-EAP
+#      eap=TTLS
+#      identity="user@example.com"
+#      anonymous_identity="anonymous@example.com"
+#      password="foobar"
+#      ca_cert="blob://exampleblob"
+#      priority=20
+#}
+
+#blob-base64-exampleblob={
+#SGVsbG8gV29ybGQhCg==
+#}
+
+# Wildcard match for SSID (plaintext APs only). This example selects any
+# open AP regardless of its SSID.
+#network={
+#      key_mgmt=NONE
+#}
diff --git a/bcm4329/src/Android.mk b/bcm4329/src/Android.mk
new file mode 100644 (file)
index 0000000..8143ba2
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2008 Broadcom Corporation
+#
+# $Id: Android.mk,v 2.1.4.3 2009/05/07 18:48:19 Exp $
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+       dhd/exe/dhdu.c \
+       dhd/exe/dhdu_linux.c \
+       shared/bcmutils.c \
+       shared/miniopt.c
+
+LOCAL_MODULE := dhdutil
+LOCAL_CFLAGS := -DSDTEST -DTARGETENV_android -Dlinux -DLINUX -mabi=aapcs-linux
+LOCAL_C_INCLUDES +=$(LOCAL_PATH)/include $(LOCAL_PATH)/../../../../kernel/include
+# LOCAL_FORCE_STATIC_EXECUTABLE := true
+# LOCAL_STATIC_LIBRARIES := libc
+LOCAL_SHARED_LIBRARIES := libc
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug tests
+
+include $(BUILD_EXECUTABLE)
+
+endif  # TARGET_SIMULATOR != true
diff --git a/bcm4329/src/GNUmakefile.inc b/bcm4329/src/GNUmakefile.inc
new file mode 100644 (file)
index 0000000..3ca3bdd
--- /dev/null
@@ -0,0 +1,580 @@
+#  Top level GNUmakefile for windows builds
+#
+#  It includes makefiles/*.mk for windows buildtype rules
+#  and sources(windows style makefile). it doesn't depend on 
+#  Makerules.env except to get SRCBASE if not yet defined. 
+#
+#  $Id: GNUmakefile.inc,v 1.103.50.1 2009/05/20 19:39:45 Exp $
+
+SHELL=bash
+export SHELL
+unexport C_DEFINES
+HOSTNAME=$(shell hostname)
+ERRORS :=
+WARNINGS :=
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+
+ifdef ECLOUD_BUILD_ID
+  CMDSHELL := $(subst \,/,$(COMSPEC))
+  CMDSTART := $(CMDSHELL) /c start /min /separate
+else # ECLOUD_BUILD_ID
+  CMDSHELL :=
+  CMDSTART :=
+endif # ECLOUD_BUILD_ID
+
+### if SRCBASE is not defined, set it to wherever Makerules.env is found
+ifndef SRCBASE
+    ifneq ($(wildcard ../Makerules.env), )
+       SRCBASE = ../
+    else       
+       ifneq ($(wildcard ../../Makerules.env), )
+               SRCBASE = ../..
+       else
+           ifneq ($(wildcard ../../../Makerules.env),)
+                   SRCBASE     = ../../..
+           else
+               ifneq ($(wildcard ../../../../Makerules.env),)
+                       SRCBASE = ../../../..
+               else
+               ifneq ($(wildcard ../../../../../Makerules.env),)
+                   SRCBASE = ../../../../..
+               else
+                   ifneq ($(wildcard ../../../../../../Makerules.env),)
+                           SRCBASE = ../../../../../..
+                   endif
+           endif
+               endif
+           endif
+       endif
+    endif
+endif # ifndef SRCBASE 
+
+ifeq ($(strip $(SRCBASE)), )
+    ERRORS += "SRCBASE is not defined!"
+    ERRORS += "This variable must be defined in your sources or GNUsources file,"
+    ERRORS += "or it may be calculated provided you are in a CVS source repository,"
+    ERRORS += "and you are not too far below the root."
+endif
+
+### if TTYPE is not defined, reinvoke this same makefile with TTYPE defined
+###retail:free:   --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=OPT all
+###debug:checked: --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG all
+###%:             --> $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@
+
+ifeq ($(origin TTYPE), undefined)
+
+all : debug free
+
+release : all
+
+unexport SRCFILE
+ifndef SRCFILE
+       SRCFILE = ./sources
+endif
+include $(SRCFILE)
+
+#   In some rare instances you may want to have the makefile synthesize
+#   explicit rules for all of your source files.  You must do this if you
+#   are building a target with multiple source files of the same name,
+#   e.g. ./utils.c and ../ntddksim/utils.c.  You might also want to use
+#   this method if you don't want to use VPATHs.
+#
+ifdef USE_SRCRULES
+
+SRCRULES=$(SRCFILE).mk
+SOURCES.CPP    := $(filter %.cpp %.CPP,$(SOURCES))
+SOURCES.C      := $(filter %.c %.C,$(SOURCES))
+
+$(SRCRULES) : $(SRCFILE)
+       @echo "building explicit source rules..."
+       @( \
+       echo "# DO NOT EDIT!!!!  DO NOT EDIT!!!!  DO NOT EDIT!!!!"; \
+       echo "# This file is automatically generated."; \
+       echo "#"; \
+       $(foreach f,$(SOURCES.C), echo '$$(OUTDIR_$$(TTYPE))/$(patsubst %.c,%.obj,$(subst /,_,$(f))) : $(f)'; echo '    $$(c-obj-command)'; echo;) \
+       $(foreach f,$(SOURCES.CPP), echo '$$(OUTDIR_$$(TTYPE))/$(patsubst %.cpp,%.obj,$(subst /,_,$(f))) : $(f)'; echo '        $$(cpp-obj-command)'; echo;) \
+       ) >$(SRCFILE).mk
+
+$(SRCFILE) :
+       echo making $@
+
+retail free :: $(SRCRULES)
+
+debug checked :: $(SRCRULES)
+
+endif # USE_SRCRULES
+
+#
+# End of rule synthesis section
+#
+
+retail free ::
+       $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=OPT all
+
+debug checked :: 
+       $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG all
+
+%GNUmakefile.inc :
+       echo making $@
+
+GNUmakefile :
+       echo making $@
+
+clean : 
+       $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@
+
+## This catch-all generic rule breaks make targets defined in module which 
+## call this makefile.
+## % : FORCE
+##     $(MAKE) -f $(SRCBASE)/GNUmakefile.inc TTYPE=DBG MAKECMDGOALS=$@ $@
+
+.PHONY: all release free checked retail debug clean FORCE
+
+
+### if TTYPE is defined, 
+###   define commands, tools and compile rules
+###   include $(SRCFILE)
+###   build all :: target ::
+else # TTYPE is defined
+
+# Define default command for printing errors and warnings.  This will
+# be redefined at the end of this makefile if any errors or warnings
+# are encountered.  
+#
+define print-errors
+endef
+
+define print-warnings
+endef
+
+# define the default command for compiling .c files into .obj files.
+# Some target types will redefine this command.
+#
+# %.obj :  %.c
+define c-obj-command
+    $(CC) -c $(C$(TTYPE)FLAGS) -I$(OUTDIR_$(TTYPE)) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $<
+endef
+
+# define the default command for compiling .cpp files into .obj files.
+# Some target types will redefine this command.
+#
+# %.obj :  %.cpp
+define cpp-obj-command
+    $(CC) -c $(C$(TTYPE)FLAGS) -I$(OUTDIR_$(TTYPE)) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $<
+endef
+
+# define the default command for compiling .asm files into .obj files.
+# Some target types will redefine this command.
+#
+# %.obj :  %.asm
+define asm-obj-command
+       $(AS) -c $(AFLAGS) $(CPPFLAGS) $(F$(TTYPE)) -Fo$@ $<
+endef
+
+# define the default command for compiling .rc files into .res files.
+# Some target types will redefine this command.
+#
+# %.res :  %.rc
+define rc-res-command
+       export INCLUDE="$(OUTDIR_$(TTYPE));$(MSINCLUDE)"; \
+       $(CMDSTART) $(RC) -r $(RCFLAGS) -fo$@ $<
+endef
+
+all ::
+       $(print-warnings)
+ifdef SHOWBUILDINFO
+       @echo " -------------------------------------------"
+       @echo " SRCFILE      = $(SRCFILE)"
+       @echo " SOURCES      = $(SOURCES)"
+       @echo " C_DEFINES    = $(C_DEFINES)"
+       @echo " WLTUNEFILE   = $(WLTUNEFILE)"
+       @echo " TARGETPATH   = $(TARGETPATH)"
+       @echo " TARGETTYPE   = $(TARGETTYPE)"
+       @echo " MAKE_VERSION = $(MAKE_VERSION)"
+       @echo " TTYPE        = $(subst OPT,OPT(free),$(subst DBG,DBG(checked),$(TTYPE)))"
+       @echo " -------------------------------------------"
+endif # SHOWBUILDINFO
+
+all ::
+       $(print-errors)
+
+include $(SRCBASE)/branding.inc
+
+ifeq ($(origin USEBCMUIO), undefined)
+#if defined(USEBCMUIO)
+USEBCMUIO=1
+#else
+# undefine USEBCMUIO
+USEBCMUIO=
+#endif
+endif
+
+BIN_OPT=retail
+BIN_DBG=debug
+BUILDENV_OPT=free
+BUILDENV_DBG=checked
+MSVSBUILDENV_OPT=Release
+MSVSBUILDENV_DBG=Debug
+OUTDIR_OPT = $(TARGETPATH)/free
+OUTDIR_DBG = $(TARGETPATH)/checked
+
+OUTDIR_FREE = $(OUTDIR_OPT)
+OUTDIR_CHECKED = $(OUTDIR_DBG)
+
+
+CC  = cl
+AS  = ml
+RC  = rc
+MC  = mc
+LD  = link
+LIBCMD = lib
+MTL = midl
+
+# Ignore any include path and lib paths that the user imports from 
+# the environment.
+#
+INCLUDE =
+
+ifeq ($(origin TARGETPATH), undefined)
+    TARGETPATH=.
+endif
+TARGETPATH := $(subst \,/,$(TARGETPATH))
+
+DDKBUILDENV := $(BUILDENV_$(TTYPE))
+MSVSBUILDENV := $(MSVSBUILDENV_$(TTYPE))
+BIN         := $(BIN_$(TTYPE))
+MC_FLAGS = -v
+
+### assume sources as entry point
+ifndef SRCFILE
+       SRCFILE=./sources
+endif
+
+include $(SRCFILE)
+SRCRULES=$(SRCFILE).mk
+
+ifeq ($(findstring $(TARGETTYPE), "EXE DRIVER LIB DLL DLL16 EXE16 DYNLINK VXD DOSEXE PROGRAM DUMMY"), )
+       ERRORS += "TARGETTYPE is not defined or not recognized!"
+       ERRORS += "This variable must be defined with a recognized value"
+       ERRORS += "in your sources or GNUsources file."
+endif
+
+# include any branding defined if they exist in the environment
+ifneq ($(BRAND),)
+    C_DEFINES += -DBRAND="'$(BRAND)'"
+endif # BRAND
+
+SOURCES.IDL    := $(filter %.idl,$(SOURCES))
+SOURCES.TLB    := $(patsubst %.idl,%.tlb,$(SOURCES.IDL))
+SOURCES._IC     := $(patsubst %.idl,%_i.c,$(SOURCES.IDL))
+
+SOURCES.OBJ    := $(SOURCES)
+SOURCES.OBJ    := $(patsubst %.cpp,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(patsubst %.CPP,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(patsubst %.asm,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(patsubst %.ASM,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(patsubst %.c,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(patsubst %.C,%.obj,$(SOURCES.OBJ))
+SOURCES.OBJ    := $(filter %.obj,$(SOURCES.OBJ))
+# SOURCES.OBJ  := $(notdir $(SOURCES.OBJ))
+SOURCES.OBJ    := $(subst /,_,$(SOURCES.OBJ))
+
+SOURCES.RES    := $(patsubst %.rc,%.res,$(filter %.rc,$(SOURCES)))
+SOURCES.MSG    := $(patsubst %.mc,%.h,$(filter %.mc,$(SOURCES)))
+
+vpath %.rc     .:..:../..
+
+
+ifdef USE_DEPENDENCIES
+
+# MAKECMDGOALS is not supported until gnumake version 3.76 so we hack
+# it by explicitly setting MAKECMDGOALS in the clean rule at the top
+# of this file.  
+#
+ifneq ($(MAKECMDGOALS),clean)
+
+# BUG -- BUG -- BUG
+# This code assumes that files are still unique without the extension.
+# So no foo.c and foo.cpp in the same makefile.
+
+SOURCES.D       :=  $(SOURCES)
+SOURCES.D       :=  $(patsubst %.c,%.d,$(SOURCES.D))
+SOURCES.D       :=  $(patsubst %.C,%.d,$(SOURCES.D))
+SOURCES.D       :=  $(patsubst %.cpp,%.d,$(SOURCES.D))
+SOURCES.D       :=  $(patsubst %.CPP,%.d,$(SOURCES.D))
+SOURCES.D       :=  $(filter %.d,$(SOURCES.D))
+
+endif  # MAKECMDGOALS != clean
+
+endif  # ifdef USE_DEPENDENCIES
+
+SI_FLAGS = -translate:always,source,package 
+
+
+
+# Target all just depends upon our target file.
+all :: target post-build-target
+
+# The target file depends upon the directory where it will reside.
+target :: $(OUTDIR_$(TTYPE))/NUL
+
+WLCFGDIR        ?= $(SRCBASE)/wl/config
+WLTUNEFILE      ?= wltunable_sample.h
+
+# Create target directory if necessary.
+$(OUTDIR_$(TTYPE))/NUL : 
+       [ -d "$(@D)" ] || mkdir -p $(@D)
+ifeq ($(WLCONF_GEN),true)
+       @if [ ! -f "$(@D)/wlconf.h" ]; then \
+           cp -v $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; \
+       elif ! diff -q $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; then \
+           cp -v $(WLCFGDIR)/$(WLTUNEFILE) $(@D)/wlconf.h; \
+       fi
+endif
+
+#
+# If the sources file specified a NTTARGETFILE0, build that first.
+#
+target :: $(NTTARGETFILE0)
+
+
+# calculate some dynamic variables that are useful in build rules.
+#
+DEPS_OBJ = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.OBJ))
+DEPS_RES = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.RES))
+DEPS_TLB = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.TLB))
+DEPS_MSG = $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.MSG))
+# Finally generate DEPENDENCIES list that are made as explicit dependencies
+# in src/makefile/<obj-type>.mk file
+DEPENDENCIES =    $(DEPS_TLB) $(DEPS_MSG) $(DEPS_OBJ) $(DEPS_RES)
+DOS_DEPS= $(shell echo $(filter-out %.tlb %.TLB %.h %.H %.def %.DEF,$^) | sed 's%//\(.\)/%\1:/%g')
+
+
+$(OUTDIR_$(TTYPE))/%.i :  %.c
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(CC) -E -P $(C$(TTYPE)FLAGS) $(CPPFLAGS) $(F$(TTYPE)) $< >$@ 
+
+$(OUTDIR_$(TTYPE))/%.i :  %.cpp
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(CC) -E -P $(C$(TTYPE)FLAGS) $(CPPFLAGS) $(F$(TTYPE)) $< >$@ 
+
+$(OUTDIR_$(TTYPE))/%.d :  %.c
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(calculate_dependencies)
+
+$(OUTDIR_$(TTYPE))/%.d :  %.C
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(calculate_dependencies)
+
+$(OUTDIR_$(TTYPE))/%.d :  %.cpp
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(calculate_dependencies)
+
+$(OUTDIR_$(TTYPE))/%.d :  %.CPP
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(calculate_dependencies)
+
+$(OUTDIR_$(TTYPE))/%.obj :  %.c
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(c-obj-command)
+
+$(OUTDIR_$(TTYPE))/%.obj :  $(OUTDIR_$(TTYPE))/%.c
+       @echo "Compiling $(notdir $<) -> $(OUTDIR_$(TTYPE))/$(notdir $@)"
+       $(c-obj-command)
+
+$(OUTDIR_$(TTYPE))/%.obj :  %.C
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(c-obj-command)
+
+$(OUTDIR_$(TTYPE))/%.obj :  %.cpp
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(cpp-obj-command)
+
+$(OUTDIR_$(TTYPE))/%.obj :  %.CPP
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(cpp-obj-command)
+
+ifdef ECLOUD_BUILD_ID
+$(OUTDIR_$(TTYPE))/%.res :  RC = rc
+endif # ECLOUD_BUILD_ID
+
+$(OUTDIR_$(TTYPE))/%.res :  %.rc
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(rc-res-command)
+
+# build rule for IDL files.
+$(OUTDIR_$(TTYPE))/%.tlb $(OUTDIR_$(TTYPE))/%.h $(OUTDIR_$(TTYPE))/%_i.c : %.idl
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(MTL) /I $(MSSDK)/include /nologo /Oicf /out $(OUTDIR_$(TTYPE)) $<
+
+# Build rule for message file
+$(OUTDIR_$(TTYPE))/%.rc $(OUTDIR_$(TTYPE))/%.h : %.mc
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(MC) -h $(OUTDIR_$(TTYPE)) -r $(OUTDIR_$(TTYPE)) $(MC_FLAGS) $<
+
+$(OUTDIR_$(TTYPE))/%.obj: %.asm
+       @echo "Compiling $(notdir $<) -> $(notdir $@)"
+       $(asm-obj-command)
+
+FORCE: 
+
+clean ::
+       rm -rf $(OUTDIR_CHECKED) $(OUTDIR_FREE) $(SRCRULES)
+
+
+ifeq  ("$(TARGETTYPE)", "DRIVER")
+ifeq  ("$(DRIVERTYPE)", "WDM")
+include $(SRCBASE)/makefiles/wdm.mk
+else
+ifeq  ("$(DRIVERTYPE)", "WDM2600")
+    include $(SRCBASE)/makefiles/wdm2600.mk
+else
+    include $(SRCBASE)/makefiles/driver.mk
+endif
+endif 
+endif 
+
+ifeq  ("$(TARGETTYPE)", "VXD")
+include $(SRCBASE)/makefiles/vxd.mk
+endif 
+
+ifneq ($(findstring x$(TARGETTYPE)x, "xDLLx xDYNLINKx"), )
+ifneq ($(findstring x$(HOSTOS)x, "xwincex"), )
+include $(SRCBASE)/makefiles/dllce.mk
+else
+include $(SRCBASE)/makefiles/dll.mk
+endif
+endif 
+
+ifneq ($(findstring $(TARGETTYPE)x, "DLL16x"), )
+include $(SRCBASE)/makefiles/dll16.mk
+endif 
+
+ifneq ($(findstring $(TARGETTYPE)x, "EXE16x"), )
+include $(SRCBASE)/makefiles/exe16.mk
+endif 
+
+ifneq ($(findstring $(TARGETTYPE), "LIB"), )
+ifneq ($(findstring x$(HOSTOS)x, "xwincex"), )
+include $(SRCBASE)/makefiles/libce.mk
+else
+include $(SRCBASE)/makefiles/lib.mk
+endif
+endif
+
+ifneq ($(findstring $(TARGETTYPE), "xEXEx xPROGRAMx"), )
+ifneq ($(findstring x$(HOSTOS)x, "xwincex"), )
+include $(SRCBASE)/makefiles/exece.mk
+else
+include $(SRCBASE)/makefiles/exe.mk
+endif
+endif 
+
+ifneq ($(findstring x$(TARGETTYPE)x, "xDOSEXEx"), )
+include $(SRCBASE)/makefiles/dosexe.mk
+endif
+
+ifneq ($(findstring $(TARGETTYPE), "DUMMY"), )
+include $(SRCBASE)/makefiles/dummy.mk
+endif
+
+# Set make variables that help find things like DDK's, SDK's, etc,
+# depending upon the requirements expressed in the individual
+# makefile(s).
+include $(SRCBASE)/makefiles/env.mk
+
+# 
+# Add some rules so that our target depends on any libraries we are going 
+# to link against.
+#
+#target :: $(LIBS)
+
+
+target :: $(OUTDIR_$(TTYPE))/$(TARGET)
+
+ifneq ($(wildcard ./makefile.inc), )
+include .\makefile.inc
+endif
+
+
+#
+# If the sources file specified a NTTARGETFILES, build that last.
+#
+
+target :: $(NTTARGETFILES)
+
+
+target :: 
+       @echo Finished compiling $@
+       @echo ""
+
+post-build-target ::
+
+release: all
+
+.PHONY: all target release clean $(OUTDIR_$(TTYPE))/.depends 
+
+ifneq ($(wildcard $(SRCRULES)), )
+include $(SRCRULES)
+endif
+
+# only try to do dependency checking if we have some dependencies to check!
+#
+# It seems counter-intiutive but it looks like the
+# include dependencies are evaluated in reverse order from their
+# appearance in the makefile.  Therefore we include the NUL file from
+# the object directory *after* we include the dependency files
+# themselves.  This results in the object directory getting created
+# before we build any of the dependency files.
+#
+ifneq ($(strip $(SOURCES.D)),)
+include $(patsubst %,$(OUTDIR_$(TTYPE))/%,$(SOURCES.D))
+include $(OUTDIR_$(TTYPE))/NUL 
+endif
+
+define calculate_dependencies
+       @ echo making $@
+       $(SHELL) -ec 'gcc -MM -w -D_M_IX86=500 $(C_DEFINES) $(CPPFLAGS) $< \
+       | sed '\''s?$*\.o[ :]*?$@ &?g'\'' >$@'
+endef
+
+ifdef OTHER_SOURCES
+all clean :: $(OTHER_SOURCES)
+       @echo "Go through OTHER_SOURCES: $(OTHER_SOURCES)"
+       $(foreach SRCFILE,$(OTHER_SOURCES),$(MAKE) SRCFILE=$(SRCFILE) TTYPE=$(TTYPE) $@; )
+endif
+
+vpath %.Lib $(LIBVPATH)
+vpath %.LIB $(LIBVPATH)
+vpath %.lib $(LIBVPATH)
+
+export PATH:=$(subst $(space),:,$(strip $(NEWPATH))):$(PATH)
+
+foo: 
+       @echo _SDKROOT=$(_SDKROOT)
+       @echo NEWPATH=$(NEWPATH)
+
+endif 
+###  end of ifeq ($(origin TTYPE), undefined)
+
+printenv:
+       env
+
+ifdef WARNING
+define print-warnings
+@echo "Warning **** Warning **** Warning **** Warning **** Warning"
+@for warn in $(WARNING) ; do echo $$warn; done
+@echo "Continuing..."
+endef
+endif # WARNING
+
+ifdef ERRORS
+define print-errors
+@echo "Error **** Error **** Error **** Error **** Error"
+@for err in $(ERRORS) ; do echo $$err; done
+@echo "Exiting makefile."
+@exit 1
+endef
+endif # ERRORS
diff --git a/bcm4329/src/Makerules b/bcm4329/src/Makerules
new file mode 100644 (file)
index 0000000..511def2
--- /dev/null
@@ -0,0 +1,546 @@
+#
+#  Top level Makerules
+#  it uses Makerules.env for build env vars and optional branding.inc
+#
+# Copyright (C) 1999-2009, Broadcom Corporation
+# 
+#      Unless you and Broadcom execute a separate written software license
+# agreement governing use of this software, this software is licensed to you
+# under the terms of the GNU General Public License version 2 (the "GPL"),
+# available at http://www.broadcom.com/licenses/GPLv2.php, with the
+# following added to such license:
+# 
+#      As a special exception, the copyright holders of this software give you
+# permission to link this software with independent modules, and to copy and
+# distribute the resulting executable under terms of your choice, provided that
+# you also meet, for each linked independent module, the terms and conditions of
+# the license of that module.  An independent module is a module which is not
+# derived from this software.  The special exception does not apply to any
+# modifications of the software.
+# 
+#      Notwithstanding the above, under no circumstances may you combine this
+# software in any way with any other Broadcom software provided under a license
+# other than the GPL, without Broadcom's express prior written consent.
+#
+# $Id: Makerules,v 2.69.30.3.2.6 2009/05/15 23:06:59 Exp $
+
+# first rule (default)
+all:
+
+# SRCBASE should be set by the Makefile that includes this.
+ifndef SRCBASE
+       SRCBASE = .
+endif
+
+# Set up the build environment variables
+include ${SRCBASE}/Makerules.env
+
+# Define space to be a single space character. Using " " gets the quotes
+# as well, which we don't want.
+empty :=
+space := $(empty) $(empty)
+
+ifeq ($(HOSTOS), Windows_NT)
+
+# force use of bash, otherwise you will get the broken sh.exe.
+SHELL=bash
+
+endif
+
+#
+# Setup make variables depending on target
+#
+
+ifeq ($(TARGETOS), unix)
+
+       # The environment for native unix builds
+
+       EXEEXT  = 
+       OBJEXT  = .o
+       GCINCS  = -I$(SRCBASE)/include
+       GCDEFS  = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+
+       ifeq ($(TARGETARCH), x86_mmx)
+               GCDEFS  := $(GCDEFS) -D_X86_ -D_MMX_
+       endif
+       ifeq ($(TARGETARCH), x86)
+               GCDEFS  := $(GCDEFS) -D_X86_
+       endif
+       ifeq ($(TARGETARCH), mips)
+               GCDEFS  := $(GCDEFS) -D_MIPS_
+       endif
+       ifeq ($(TARGETARCH), mips_be)
+               GCDEFS  := $(GCDEFS) -D_MIPS_ -DIL_BIGENDIAN
+       endif
+       ifeq ($(TARGETARCH), arm)
+               GCDEFS  := $(GCDEFS) -D_ARM_ -DIL_BIGENDIAN
+       endif
+       ifeq ($(TARGETARCH), arm_le)
+               GCDEFS  := $(GCDEFS) -D_ARM_
+       endif
+       ifeq ($(TARGETARCH), arm_android)
+               GCDEFS  := $(GCDEFS) -D_ARM_
+       endif
+
+       ifeq ($(TARGETENV), freebsd)
+               GCINCS  := $(GCINCS) -I/usr/local/include
+       endif
+       ifeq ($(TARGETENV), sun4)
+               GCDEFS  := $(GCDEFS) -D_SPARC_
+       endif
+       ifeq ($(TARGETENV), macos)
+               MACOS_VER := $(shell sw_vers -productVersion)
+
+               ifneq (,$(findstring 10.5,$(MACOS_VER)))
+                       SDK=/Developer/SDKs/MacOSX10.5.sdk
+               else
+                       SDK=/Developer/SDKs/MacOSX10.4u.sdk
+               endif
+
+               GCDEFS  := $(GCDEFS) -DMACOSX
+               GCDEFS  := $(GCDEFS) -pipe -fpascal-strings -fasm-blocks -fmessage-length=0
+               GCDEFS  := $(GCDEFS) -fvisibility=hidden -isysroot $(SDK)
+
+               ifeq ($(TARGETARCH), PPC)
+                       GCDEFS  := $(GCDEFS) -arch ppc -mtune=G4
+                       GLDFLAGS = -arch ppc -Wl,-syslibroot,$(SDK)
+               endif
+               ifeq ($(TARGETARCH), x86)
+                       GCDEFS  := $(GCDEFS) -arch i386
+                       GLDFLAGS = -arch i386 -Wl,-syslibroot,$(SDK)
+               endif
+       endif
+
+       GCOPTS  =
+       GCFLAGS = -g -Wall
+
+       CC_TARGET       =-o $@
+       LINK_TARGET     =-o $@
+
+       ifeq ($(TARGETENV), linuxmips)
+               TARGET_PREFIX = mipsel-linux-
+       else
+       ifeq ($(TARGETENV), linuxmips_be)
+               TARGET_PREFIX = mips-linux-
+       else
+       ifeq ($(TARGETENV), linuxarm)
+               TARGET_PREFIX = armeb-linux-
+       else
+       ifeq ($(TARGETENV), linuxarm_le)
+               TARGET_PREFIX = arm-linux-
+       else
+       ifeq ($(TARGETENV), android)
+               TARGET_PREFIX = arm-eabi-
+               GCFLAGS += -Dlinux
+               GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/include
+               GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/arch-arm/include/
+               GCFLAGS += -I/tools/linux/src/linux-2.6.25-01843-gfea26b0/include/
+       else
+       ifeq ($(TARGETENV), linuxarm_omap)
+               TARGET_PREFIX = arm-none-linux-gnueabi-
+       else
+               TARGET_PREFIX =
+       endif
+       endif
+       endif
+       endif
+       endif
+       endif
+
+       CC = $(TARGET_PREFIX)gcc
+       AS = $(TARGET_PREFIX)as
+       LD = $(TARGET_PREFIX)ld
+       AR = $(TARGET_PREFIX)ar
+
+       INSTALL = install -c
+
+       TCFLAGS =
+
+       ifeq ($(TARGETENV), freebsd)
+               GLDFLAGS = -static
+       endif
+       ifeq ($(TARGETENV), linuxarm)
+               GLDFLAGS = -static
+       endif
+       ifeq ($(TARGETENV), linuxarm_le)
+               GLDFLAGS = -static
+       endif
+       ifeq ($(TARGETENV), android)
+               GLDFLAGS = -static
+       endif
+       ifeq ($(TARGETENV), linuxarm_omap)
+               GLDFLAGS = -static
+       endif
+
+       GLDLIBS = -lgcc
+
+endif  # $(TARGETOS) == unix
+
+ifeq ($(TARGETOS), Windows_NT)
+
+       # The environment for windows builds
+
+       EXEEXT = .exe
+
+       ifeq ($(TARGETENV), win32)
+               # standard win32 using MS compiler
+               OBJEXT  = .obj
+               GCINCS  = /I$(SRCBASE)/include
+               GCDEFS  = /DTARGETENV_$(TARGETENV) /DTARGETOS_$(TARGETOS) \
+                       /DTARGETARCH_$(TARGETARCH) /D_X86_
+               ifeq ($(TARGETARCH), x86_mmx)
+                       GCDEFS += /D_MMX_
+               endif
+               GCOPTS  = /nologo
+               GCFLAGS = /GM /W3 /Z7
+
+               CC_TARGET       =-Fo$@
+               LINK_TARGET     =-out:$@
+
+               CC = cl
+               AS = cl
+               LD = cl
+
+               TCFLAGS =
+               GLDFLAGS = /nologo /link /nologo /INCREMENTAL:NO
+
+               GLDLIBS =
+       else
+               # cygwin32 based environment
+               OBJEXT  = .o
+               GCINCS  = -I$(SRCBASE)/include
+               GCDEFS  = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+                       -DTARGETARCH_$(TARGETARCH) -D_X86_
+               ifeq ($(TARGETARCH), x86_mmx)
+                       GCDEFS += -D_MMX_
+               endif
+               GCOPTS  =
+               GCFLAGS = -g -Wall
+
+               CC_TARGET       =-o $@
+               LINK_TARGET     =-o $@
+
+               CC = gcc
+               AS = gcc
+               LD = gcc
+               INSTALL = install -c
+
+               TCFLAGS =
+               GLDFLAGS =
+
+               GLDLIBS = -liberty -lgcc
+       endif
+
+       # Tools common to cygwin/win32
+
+       INSTALL = install -c
+       BUILD = build -ceZ
+
+       # RELEASE_TARGET is a the directory under RELEASE_DIR where
+       # target dependant files go. It is composed of the OS and
+       # the CPU, some examples are: winnt40/i386, win98 ...
+       #
+       # NEEDSWORK: For now only NT 4.0 stuff uses it.
+       ifneq ($(findstring $(TARGETPLATFORM), "Wdm wdm"), )
+               RELEASE_TARGET = wdm/i386
+       else
+               RELEASE_TARGET = winnt40/i386
+       endif
+
+       # RELEASE_TOOLS_DIR is a the directory under RELEASE_DIR where
+       # common tools go.
+       # For compatability with previous installs &test scripts, old
+       # tools still go in "yosemite".
+       RELEASE_YOS_DIR = yosemite
+       RELEASE_TOOLS_DIR = tools
+
+endif  # $(TARGETOS) == Windows_NT
+
+ifeq ($(TARGETOS), vxWorks)
+       WIND_REGISTRY = sol
+       ifndef WIND_BASE
+               ifeq ($(HOSTOS), unix)
+                       WIND_BASE = /dfs/tools/vxWorks
+               else
+                       WIND_BASE = z:/tools/vxWorks
+               endif
+       endif
+       include $(WIND_BASE)/target/h/make/defs.default
+
+       ifeq ($(HOSTENV), Windows_NT)
+               WIND_HOST_TYPE = x86-win32
+       else
+               ifeq ($(HOSTENV), sun4)
+                       WIND_HOST_TYPE = sun4-solaris2
+               else
+                       WIND_HOST_TYPE = i386-freebsd
+               endif
+       endif
+
+       ifeq ($(TARGETENV), vxsim)
+               CPU = SIMSPARCSOLARIS
+       else
+               ifeq ($(TARGETENV), vx386)
+                       CPU = i386
+               else
+                       CPU = R4650
+                       VXFLAGS  = -DCPU_VAR=$(CPU)
+               endif
+       endif
+
+       include $(WIND_BASE)/target/h/make/make.$(CPU)$(TOOL)
+       include $(WIND_BASE)/target/h/make/defs.$(WIND_HOST_TYPE)
+
+       GCINCS  = -I$(WIND_BASE)/target/h -I$(SRCBASE)/include
+       GCDEFS  = $(DEFINE_CC) -DCPU=$(CPU) -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+       GCOPTS  = -g -O2
+       GCFLAGS = -Wall $(CC_ARCH_SPEC)
+       LDFLAGS = $(GLDFLAGS) $(LLDFLAGS)
+       GLDLIBS = $(LIBS)
+
+       WIND_BIN = $(WIND_BASE)/host/$(WIND_HOST_TYPE)/bin
+
+       AR      := $(WIND_BIN)/$(AR)
+       AS      := $(WIND_BIN)/$(AS)
+       BINHEX  := $(WIND_BIN)/$(BINHEX)
+       CC      := $(WIND_BIN)/$(CC)
+       CF      := $(WIND_BIN)/$(CF)
+       LD      := $(CC)
+       NM      := $(WIND_BIN)/$(NM)
+       RANLIB  := $(WIND_BIN)/$(RANLIB)
+       BINXSYM_NAME := $(WIND_BIN)/$(BINXSYM)
+
+endif  # $(TARGETOS) == vxWorks
+
+ifeq ($(TARGETENV), nucleusarm)
+
+       # The environment for nucleus builds
+       ifeq ($(BSP_BASE_DIR),)
+               BSP_BASE_DIR := $(SRCBASE)/../bsp
+       endif
+   
+       ifeq ($(NUCLEUS_INC_DIR),)
+               NUCLEUS_INC_DIR := $(BSP_BASE_DIR)/rtos/nucleus/inc
+       endif
+
+       EXEEXT  := 
+       OBJEXT  := .o
+       GCINCS  := -I$(SRCBASE)/include -I$(NUCLEUS_INC_DIR)
+       GCDEFS  := -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) -DTARGETARCH_$(TARGETARCH)
+       GCOPTS  :=
+   
+       ifeq ($(OBJDIR),)
+               OBJDIR  := $(TARGETENV)/
+       endif
+   
+       # --md:  This option compiles the source and writes make file dependency lines 
+       #        to a file. The output file is suitable for use by a make utility.
+       # -c:    Compiles but does not perform the link phase.
+       # -O2:   High optimization.
+       # ---memaccess -UL41: This option tells the compiler that the memory in the 
+       #        target system has slightly restricted or expanded capabilities.
+       #        Disables unaligned mode for code that uses pre-ARMv6 unaligned 
+       #        access behavior.
+       # "/adsabi" is added to "--apcs /interwork/$(SWST)" so that objects created
+       #       under ADS 1.2 can be linked with objects compiled under RVCT 2.2.
+       # --diag_suppress 2084,1658 = blocks the diagnostic warning "Warning: C2084W: support for --apcs /adsabi is deprecated"
+       #                 1293: Suppress "Assignment in condition" warning.
+       GCFLAGS := --md \
+                       -c \
+                       -O2 \
+                       --memaccess -UL41 \
+                       --apcs /adsabi/interwork/NOSWST \
+                       --diag_suppress 2084,1658,1293 \
+                       --li
+
+       # --cpu 'name': This option generates code for a specific ARM processor or architecture.
+       ifeq ($(TARGETCPU),2153)
+               GCFLAGS += --cpu ARM1136J-S
+       else
+      $(error "Unknown target CPU type!")
+       endif
+
+       #CPPFLAGS       := -embeddedcplusplus
+
+       CC_TARGET       =-o $@
+       CPP_TARGET      =-o $@
+       LINK_TARGET     =-o $@
+
+       CC := tcc
+       CPP := tcpp
+       AS := armasm
+       LD := armlink
+       AR := armar -c -r --create
+
+       INSTALL := install -c
+
+       TCFLAGS :=
+
+       GLDFLAGS := 
+       GLDLIBS := --ELF --symbols --debug --map --info sizes,totals --errors link.err --list link.map --verbose
+
+       # Convert windows style directories to cygwin style.
+       # It should be used in situations where the host environment is cygwin, and
+       # the host compiler is a native Win32 app (non-cygwin). It will convert the 
+       # Windows style directories in the dependencies list to cygwin style. This is
+       # necessary for the dependency files to be included by cygwin make.
+       ifeq ($(HOSTOS),Windows_NT)
+               FILTER_DEPENDS_IN_C_TO_OBJ_RULE := 1
+       endif
+
+endif  # $(TARGETENV) == nucleusarm
+
+ifeq   ($(TARGETENV), bcmmips)
+
+       OBJEXT  = .o
+       GCINCS  = -I$(SRCBASE)/include
+       GCDEFS  = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+               -DTARGETARCH_$(TARGETARCH) -D__mips__
+       GCOPTS  = -g -O2
+       GCFLAGS = -Wall 
+       GLDFLAGS = -Wl,-tidt.dld
+
+       AS              = bcmas
+       CC              = bcmgcc
+       LD              = $(CC)
+       NM              = bcmnm
+       RANLIB          = bcmranlib
+
+endif  # $(TARGETENV) == bcmmips
+
+ifeq   ($(TARGETENV), klsi)
+
+       OBJEXT  = .obj
+       GCINCS  = -I$(SRCBASE)/include
+       GCDEFS  = -DTARGETENV_$(TARGETENV) -DTARGETOS_$(TARGETOS) \
+               -DTARGETARCH_$(TARGETARCH) -D__klsi__
+
+       AS              = qtasm
+       GASFLAGS        = -m20
+       CC              = qtcc
+       TCFLAGS         = -w asm=$(GASFLAGS) +c -Vcdv -w cc=+reginfo
+
+endif  # $(TARGETENV) == klsi
+
+CFLAGS = $(LCINCS) $(GCINCS) $(GCDEFS) $(GCOPTS) $(GCFLAGS) $(TCFLAGS) $(HCFLAGS) \
+$(LCDEFS) $(LCOPTS) $(LCFLAGS) $(CENV)
+
+ASFLAGS        = $(GASFLAGS) $(LASFLAGS) $(ASENV)
+LDFLAGS        = $(GLDFLAGS) $(LLDFLAGS) $(LDENV)
+LDLIBS = $(LLDLIBS) $(GLDLIBS)
+
+# dependency files including the .d file itself.
+# note the example in GNU documentation seems to have a bug:
+# two backslashes where one is correct.
+%.d: %.c
+ifeq ($(findstring s, $(MAKEFLAGS) ),)
+       @ echo making $@
+endif
+       @ $(SHELL) -ec '$(CC) -MM $(CFLAGS) $(CPPFLAGS) $< \
+       | sed '\''s/$*\.o[ :]*/$@ &/g'\'' >$@'
+
+ifeq ($(TARGETENV), win32)
+
+# win32 needs different command line args 
+
+%.s: %.c
+       $(CC) /FAs $(CFLAGS) $(CPPFLAGS) /Fa$@ /c $<
+
+%.i: %.c
+       $(CC) /E $(CFLAGS) $(CPPFLAGS) $< > $@
+
+else # !win32
+
+%.s: %.c
+       $(CC) -S $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+%.i: %.c
+       $(CC) -o $@ -E -dD $(CFLAGS) $(CPPFLAGS) $<
+
+endif # win32
+
+ifeq   ($(TARGETENV), klsi)
+
+%$(OBJEXT): %.c
+       $(CC) $(CFLAGS) $*.c
+
+%$(OBJEXT): %.asm
+       $(AS) $(ASFLAGS) $*.asm
+
+%.asm: %.c
+       $(CC) $(CFLAGS) -asm $*.c
+
+%.i: %.c
+       $(CC) $(CFLAGS) -cc -peep -asm $*.c
+       mv $*.pp $*.i
+
+else
+
+
+# This command sequence will:
+#  - Convert back-slashes to foward-slashes
+#  - Convert long filenames to 8.3 format (e.g. Program Files --> PROGRA~1)
+#  - Convert windows-style drive letters to cygwin style.
+#
+# It should be used in situations where the host environment is cygwin, and
+# the host compiler is a native Win32 app (non-cygwin). It will convert the 
+# Windows style directories in the dependencies list to cygwin style. This is
+# necessary for the dependency files to be included by cygwin make.
+define FILTER_DEPENDS
+       sed -e 's/\\/\//g'              \
+               -e 's/Program Files/PROGRA~1/g' \
+               -e 's/\([A-Za-z]\):\//\/cygdrive\/\1\//' < $(notdir $(@:.o=.d)) > $(@:.o=.d) && \
+       rm -f $(notdir $(@:.o=.d))
+endef
+
+
+$(OBJDIR)%$(OBJEXT): %.c
+       $(CC) -c $(CFLAGS) $(CPPFLAGS) $(CC_TARGET) $<
+ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1)
+       ${FILTER_DEPENDS}
+endif   
+
+$(OBJDIR)%$(OBJEXT): %.cpp
+       $(CPP) -c $(CFLAGS) $(CPPFLAGS) $(CPP_TARGET) $<
+ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1)
+       ${FILTER_DEPENDS}
+endif   
+
+
+endif # klsi
+
+%.h: %.x
+       rpcgen -C -h $< > $@
+
+%_xdr.c: %.x
+       @ (if [ ! -f `basename $<` ] ; then ln -s $< . ; fi; true)
+       rpcgen -C -c -i 0 `basename $<` > $@
+
+# Makefile debugging rule
+env:
+       printenv
+
+# if the user mistakenly specified RELEASE_DIR in unix-style notation,
+# convert it to Win32 notation for them.
+#
+# RELEASE_DIR is assumed to be in windows-style notation if it has both 
+# backslashes ('\') and colons (':').
+#
+
+ifneq  ("$(subst \,,$(RELEASE_DIR))", "$(RELEASE_DIR)")
+ifneq  ("$(subst :,,$(RELEASE_DIR))", "$(RELEASE_DIR)")
+RELEASE_DIR := $(subst :,,$(RELEASE_DIR))
+RELEASE_DIR := $(subst \,/,$(RELEASE_DIR))
+RELEASE_DIR := //$(RELEASE_DIR)
+endif
+endif
+
+# all release rules depend on a valid RELEASE_DIR
+release: check_release_dir
+check_release_dir:
+       @if [ "x$(RELEASE_DIR)" = "x" ]; then \
+               echo "RELEASE_DIR is not set!"; \
+               exit 1; \
+       fi;
+
+include ${SRCBASE}/branding.inc
diff --git a/bcm4329/src/Makerules.env b/bcm4329/src/Makerules.env
new file mode 100644 (file)
index 0000000..dbe4c39
--- /dev/null
@@ -0,0 +1,137 @@
+#*******************************************************************************
+# $Id: Makerules.env,v 2.30.208.4 2009/01/27 01:22:16 Exp $
+# Top-level Makerules for defining environment variables
+# can be included by anyone doing software at Epigram
+#*******************************************************************************
+
+# HOSTOS is either unix or Windows_NT.
+# HOSTENV differentiates HOSTOS and is either freebsd, sun4, or Windows_NT.
+# This refers to the *BUILD* environment. All environments use "GNU C" 
+# except Windows_NT which may use "GNU C" or "Microsoft C".
+
+ifndef HOSTENV
+    # Figure what type of host we are in. 
+    UNAME = $(shell uname)
+
+    ifneq ($(findstring "$(UNAME)", "FreeBSD" "NetBSD"), )
+       HOSTENV = freebsd
+       HOSTOS = unix
+    else
+       ifneq ($(findstring "$(UNAME)", "sun4" "SunOS"), )
+           HOSTENV = sun4
+           HOSTOS = unix
+       else
+           ifeq ($(UNAME), Linux)
+               HOSTENV = linux
+               HOSTOS = unix
+           else
+               ifneq ($(findstring "$(UNAME)", "CYGWIN32_NT" "CYGWIN32/NT" "i386" "CYGWIN_NT-4.0" "CYGWIN_NT-5.0" "CYGWIN_NT-5.1" "CYGWIN_NT-5.2" "i586" "i686"), )
+                   HOSTENV = Windows_NT
+                   HOSTOS = Windows_NT
+               else
+                   ifeq ($(UNAME), Darwin)
+                       HOSTENV = macos
+                       HOSTOS = unix
+                   else        
+                       HOSTENV = unknown
+                       HOSTOS = unknown
+                   endif
+               endif
+           endif
+       endif
+    endif
+endif
+# In case we just defined them, make sure they are known
+export HOSTENV
+export HOSTOS
+       
+# TARGETENV is one of freebsd, sun4, linux, linuxarm, linuxmips, android, cygwin32, win32, or macos
+# TARGETENV defaults to HOSTENV unless HOSTENV is Windows_NT, in
+# which case it defaults to win32.
+
+ifndef TARGETENV
+    ifeq ($(HOSTENV), Windows_NT)
+       TARGETENV = win32
+    else
+        TARGETENV = $(HOSTENV)
+    endif
+endif
+export TARGETENV
+
+# TARGETOS defaults to HOSTOS in most cases
+ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "linuxarm" "linuxarm_le" "android" "linuxarm_omap" "linuxmips" "sun4" "cygwin32" "win32" "macos"), )
+    TARGETOS = $(HOSTOS)
+endif
+ifeq   ($(TARGETENV), bcmmips)
+    TARGETOS = bcmmips
+endif
+ifeq   ($(TARGETENV), klsi)
+    TARGETOS = klsi
+endif
+ifeq   ($(TARGETENV), nucleusarm)
+    TARGETOS = nucleus
+endif
+ifndef TARGETOS
+    TARGETOS = unknown
+endif
+export TARGETOS
+
+# TARGETARCH is the target processor architecture
+# Currently valid values are: x86, x86_mmx, sparc, unknown, or a list of any
+# of the valid values.
+# For the x86* family, a generic x86 is assuemd if not otherwise specified
+# Order is important since "linux" matches both linuxmips and linux.
+ifndef TARGETARCH
+    ifneq ($(findstring "$(TARGETENV)", "android"), )
+       TARGETARCH = arm_android
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "linuxarm_le"), )
+       TARGETARCH = arm_le
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "linuxarm" "nucleusarm"), )
+       TARGETARCH = arm
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "linuxarm_omap"), )
+       TARGETARCH = arm_omap
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "bcmmips" "linuxmips"), )
+       TARGETARCH = mips
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "sun4"), )
+       TARGETARCH = sparc
+    endif
+    ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "cygwin32" "win32"), )
+       TARGETCPU = $(shell uname -m)
+       ifneq ($(findstring "$(TARGETCPU)", "sparc" "sparc64"), )
+               TARGETARCH = $(TARGETCPU)
+       else
+               TARGETARCH = x86_mmx
+       endif
+    endif
+    ifeq       ($(TARGETENV), macos)
+       TARGETCPU = $(shell uname -p)
+       ifneq ($(findstring "$(TARGETCPU)", "powerpc"), )
+               TARGETARCH = PPC
+       else
+               TARGETARCH = x86
+       endif
+    endif
+    ifeq       ($(TARGETENV), klsi)
+       TARGETARCH = klsi
+    endif
+    ifndef TARGETARCH
+       TARGETARCH = unknown
+    endif
+endif
+export TARGETARCH
+
+# TARGET_TYPE is either "all" or one or more of: float64, float32, int16
+# default is int16.  "all" will get expanded into a list of all possible types
+ifndef  TARGET_TYPE
+       TARGET_TYPE = int16
+endif
+        
+ifeq ($(TARGET_TYPE), all)
+       TARGET_TYPE = int16 float32 float64
+endif
+export TARGET_TYPE
diff --git a/bcm4329/src/bcmsdio/linux/Makefile b/bcm4329/src/bcmsdio/linux/Makefile
new file mode 100644 (file)
index 0000000..9e265d4
--- /dev/null
@@ -0,0 +1,203 @@
+
+# GNU Makefile for Broadcom BCMSDH Lower-level Driver
+#
+# Copyright (C) 1999-2009, Broadcom Corporation
+# 
+#      Unless you and Broadcom execute a separate written software license
+# agreement governing use of this software, this software is licensed to you
+# under the terms of the GNU General Public License version 2 (the "GPL"),
+# available at http://www.broadcom.com/licenses/GPLv2.php, with the
+# following added to such license:
+# 
+#      As a special exception, the copyright holders of this software give you
+# permission to link this software with independent modules, and to copy and
+# distribute the resulting executable under terms of your choice, provided that
+# you also meet, for each linked independent module, the terms and conditions of
+# the license of that module.  An independent module is a module which is not
+# derived from this software.  The special exception does not apply to any
+# modifications of the software.
+# 
+#      Notwithstanding the above, under no circumstances may you combine this
+# software in any way with any other Broadcom software provided under a license
+# other than the GPL, without Broadcom's express prior written consent.
+#
+# $Id: Makefile,v 1.5.8.4.6.1 2009/01/26 20:28:33 Exp $
+#
+
+# Try a couple of places for LINUXDIR if not specified
+ifeq ($(LINUXDIR),)
+ifeq ($(LINUXVER),)
+# Neither one is specified, use uname for version
+LINUXVER := $(shell uname -r)
+endif
+ifneq ($(wildcard /lib/modules/$(LINUXVER)/build/include/linux/version.h),)
+LINUXDIR := /lib/modules/$(LINUXVER)/build
+else
+ifneq ($(wildcard /tools/linux/src/linux-$(LINUXVER)/include/linux/version.h),)
+LINUXDIR := /tools/linux/src/linux-$(LINUXVER)
+else
+LINUXDIR := /usr/src/linux
+endif
+endif
+endif
+
+LINUXVER := $(shell { cat $(LINUXDIR)/Makefile; \
+       echo "bcm$$$$:;@echo \$$(KERNELRELEASE)"; } | \
+       $(MAKE) --no-print-directory $(if $(ARCH),ARCH=$(ARCH),) -C $(LINUXDIR) -f - bcm$$$$)
+
+# check if 2.4 kernel or 2.5+ kernel
+BCM_KVER:=$(shell echo $(LINUXVER) | cut -c1-3 | sed 's/2\.[56]/2\.6/')
+
+# Allow CROSS_COMPILE to specify compiler base
+CC := $(CROSS_COMPILE)gcc
+LD := $(CROSS_COMPILE)ld
+NM := $(CROSS_COMPILE)nm
+OBJCOPY := $(CROSS_COMPILE)objcopy
+
+# driver source base and C file path
+ifeq ($(SRCBASE),)
+SRCBASE := $(shell /bin/pwd)/../..
+endif
+vpath %.c $(SRCBASE)/shared $(SRCBASE)/bcmsdio/sys $(SRCBASE)/wl/sys
+
+## Initialize DFLAGS
+DFLAGS :=
+
+
+# basic options (defines in DFLAGS, includes in IFLAGS)
+DFLAGS += -DLINUX -DSRCBASE=\"$(SRCBASE)\" -DBCMDRIVER -DBCMSDH_MODULE
+DFLAGS += -DBCMDONGLEHOST
+DFLAGS += -DBCM4325
+
+IFLAGS := -I$(LINUXDIR)/include -I$(LINUXDIR)/include/asm/mach-default -I. -I$(SRCBASE)/include -I$(SRCBASE)/shared -I$(SRCBASE)/dongle -I$(SRCBASE)/wl/sys
+
+WFLAGS := -Wall -Wstrict-prototypes
+ifeq (,$(findstring 2.4.18,$(LINUXVER)))
+WFLAGS += -Werror
+endif
+
+CFILES:= bcmsdh_linux.c linux_osl.c bcmsdh.c
+CFILES += siutils.c sbutils.c aiutils.c bcmutils.c hndpmu.c
+
+OFILES=$(CFILES:.c=.o)
+
+# Make debug a separate option
+ifneq ($(findstring -debug-,-$(TARGET)-),)
+DFLAGS += -DBCMDBG -DSDTEST
+endif
+
+# Make big-endian a separate option
+ifneq ($(findstring -be-,-$(TARGET)-),)
+DFLAGS += -DIL_BIGENDIAN
+endif
+
+ifneq ($(findstring -sdstd,$(TARGET)-),)
+DFLAGS += -DBCMSDIO -DBCMSDIOH_STD
+CFILES += bcmsdstd.c bcmsdstd_linux.c
+endif
+ifneq ($(findstring -intc1,$(shell echo $(LINUXVER))),)
+DFLAGS += -DSANDGATE2G
+endif
+ifneq ($(findstring -sdspi-,$(TARGET)-),)
+DFLAGS += -DBCMSDIO -DBCMSDIOH_SPI -DTESTDONGLE
+CFILES += bcmsdspi.c bcmsdspi_linux.c 
+endif
+
+CFLAGS += -fshort-wchar $(DFLAGS) $(WFLAGS) $(IFLAGS)
+
+LDFLAGS := -r
+MODULES := bcmsdh_driver.o
+ifeq ($(BCM_KVER), 2.6)
+  ##Kernel module names in 2.6 kernel have .ko suffix
+  KMODULES:=bcmsdh_driver.ko
+else
+  KMODULES:=$(MODULES)
+endif
+
+# host options
+HOSTCC := $(CC)
+ifneq ($(BCM_KVER), 2.6)
+  HOSTCFLAGS := $(CFLAGS) $(shell $(MAKE) --no-print-directory -s -C $(LINUXDIR) script 'SCRIPT=@echo $$(CFLAGS) $$(MODFLAGS)')
+else
+  HOSTCFLAGS := $(CFLAGS) -D__KERNEL__
+  BCMSDHCFLAGS = $(HOSTCFLAGS) -I$(shell pwd)
+  export BCMSDHCFLAGS
+  BCMSDHOFILES = $(OFILES)
+  export BCMSDHOFILES
+endif
+
+TARGETS := \
+       bcmsdh-sdstd
+ifneq ($(findstring -intc1,$(shell echo $(LINUXVER))),)
+TARGETS := bcmsdh-sdiofd
+endif
+TARGETS += $(foreach tgt, $(TARGETS), $(tgt)-debug)
+
+OBJDIR=$(TARGET)-$(LINUXVER)$(if $(BCMQT),-bcmqt)
+
+all: $(TARGETS)
+sdspi: $(filter %-sdspi-pci %-sdspi-cheetah, %-sdspi-u2c $(TARGETS))
+
+# Allow making target with the LINUXVER suffix already on it.
+# (Typical of command line tab completion; trailing slash still not allowed)
+%-$(LINUXVER): force
+       $(MAKE) $(@:%-$(LINUXVER)=%)
+
+$(TARGETS):
+       @echo "MAKING $@"
+       $(MAKE) TARGET=$@ objdir
+
+objdir:
+       @echo "Making objdir $(OBJDIR)"
+       @echo "TARGET is $(TARGET)"
+       mkdir -p $(OBJDIR)
+       $(MAKE) -C $(OBJDIR) -f ../Makefile SRCBASE=$(SRCBASE) dep
+       $(MAKE) -C $(OBJDIR) -f ../Makefile SRCBASE=$(SRCBASE) modules
+ifeq ($(BCM_KVER), 2.6)
+       $(OBJCOPY) --strip-unneeded $(OBJDIR)/bcmsdh_driver.ko $(OBJDIR)/bcmsdh_driver.ko.stripped
+else
+       $(OBJCOPY) --strip-unneeded $(OBJDIR)/bcmsdh_driver.o $(OBJDIR)/bcmsdh_driver.o.stripped
+endif
+
+dep: $(foreach file,$(CFILES),.$(file).depend)
+.%.c.depend: %.c
+       $(HOSTCC) $(HOSTCFLAGS) -M $< > $@
+.%.c.depend::
+       touch $@
+
+ifeq ($(BCM_KVER), 2.6)
+modules: $(OFILES)
+       test -r ./Makefile || ln -s ../makefile.26 ./Makefile
+       $(MAKE) -C $(LINUXDIR) M=$(shell pwd) $(if $(VERBOSE),V=1) modules
+else
+modules: $(MODULES)
+endif
+
+bcmsdh_driver.o: $(OFILES)
+       $(LD) $(LDFLAGS) -o $@ $^
+
+ifeq ($(BCM_KVER), 2.6)
+%.o: %.c
+  # when make is called from 2.6, vpath doesn't work so we need to link the files.
+       test -r ./$< || ln -s $< .
+else
+%.o: %.c
+       $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
+       @( \
+       echo 'ifneq ($$(HOSTCFLAGS),$(HOSTCFLAGS))' ; \
+       echo '$@: force' ; \
+       echo 'endif' ; \
+       ) > .$*.c.flags
+endif
+
+force:
+
+clean:
+       rm -rf bcmsdh-*
+
+ifneq ($(wildcard .*.depend),)
+include $(wildcard .*.depend)
+endif
+ifneq ($(wildcard .*.flags),)
+include $(wildcard .*.flags)
+endif
diff --git a/bcm4329/src/bcmsdio/linux/makefile.26 b/bcm4329/src/bcmsdio/linux/makefile.26
new file mode 100644 (file)
index 0000000..ffbde11
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Makefile fragment for Linux 2.6
+# Broadcom BCMSDH Driver
+#
+# Copyright (C) 1999-2009, Broadcom Corporation
+# 
+#      Unless you and Broadcom execute a separate written software license
+# agreement governing use of this software, this software is licensed to you
+# under the terms of the GNU General Public License version 2 (the "GPL"),
+# available at http://www.broadcom.com/licenses/GPLv2.php, with the
+# following added to such license:
+# 
+#      As a special exception, the copyright holders of this software give you
+# permission to link this software with independent modules, and to copy and
+# distribute the resulting executable under terms of your choice, provided that
+# you also meet, for each linked independent module, the terms and conditions of
+# the license of that module.  An independent module is a module which is not
+# derived from this software.  The special exception does not apply to any
+# modifications of the software.
+# 
+#      Notwithstanding the above, under no circumstances may you combine this
+# software in any way with any other Broadcom software provided under a license
+# other than the GPL, without Broadcom's express prior written consent.
+#
+# $Id: makefile.26,v 1.2.22.2 2008/05/07 00:20:04 Exp $
+
+obj-m += bcmsdh_driver.o
+bcmsdh_driver-objs = $(BCMSDHOFILES)
+EXTRA_CFLAGS = $(BCMSDHCFLAGS)
diff --git a/bcm4329/src/bcmsdio/sys/bcmpcispi.c b/bcm4329/src/bcmsdio/sys/bcmpcispi.c
new file mode 100644 (file)
index 0000000..ba3e0c5
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * Broadcom SPI over PCI-SPI Host Controller, low-level hardware driver
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmpcispi.c,v 1.22.2.4.4.5 2008/07/09 21:23:30 Exp $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#include <sdio.h>              /* SDIO Specs */
+#include <bcmsdbus.h>          /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>           /* to get msglevel bit values */
+
+#include <pcicfg.h>
+#include <bcmsdspi.h>
+#include <bcmspi.h>
+#include <bcmpcispi.h>         /* BRCM PCI-SPI Host Controller Register definitions */
+
+
+/* ndis_osl.h needs to do a runtime check of the osh to map
+ * R_REG/W_REG to bus specific access similar to linux_osl.h.
+ * Until then...
+ */
+/* linux */
+
+#define SPIPCI_RREG R_REG
+#define SPIPCI_WREG W_REG
+
+
+#define        SPIPCI_ANDREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) & (v)))
+#define        SPIPCI_ORREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) | (v)))
+
+
+int bcmpcispi_dump = 0;                /* Set to dump complete trace of all SPI bus transactions */
+
+typedef struct spih_info_ {
+       uint            bar0;           /* BAR0 of PCI Card */
+       uint            bar1;           /* BAR1 of PCI Card */
+       osl_t           *osh;           /* osh handle */
+       spih_pciregs_t  *pciregs;       /* PCI Core Registers */
+       spih_regs_t     *regs;          /* SPI Controller Registers */
+       uint8           rev;            /* PCI Card Revision ID */
+} spih_info_t;
+
+
+/* Attach to PCI-SPI Host Controller Hardware */
+bool
+spi_hw_attach(sdioh_info_t *sd)
+{
+       osl_t *osh;
+       spih_info_t *si;
+
+       sd_trace(("%s: enter\n", __FUNCTION__));
+
+       osh = sd->osh;
+
+       if ((si = (spih_info_t *)MALLOC(osh, sizeof(spih_info_t))) == NULL) {
+               sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh)));
+               return FALSE;
+       }
+
+       bzero(si, sizeof(spih_info_t));
+
+       sd->controller = si;
+
+       si->osh = sd->osh;
+       si->rev = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_REV, 4) & 0xFF;
+
+       if (si->rev < 3) {
+               sd_err(("Host controller %d not supported, please upgrade to rev >= 3\n", si->rev));
+               MFREE(osh, si, sizeof(spih_info_t));
+               return (FALSE);
+       }
+
+       sd_err(("Attaching to Generic PCI SPI Host Controller Rev %d\n", si->rev));
+
+       /* FPGA Revision < 3 not supported by driver anymore. */
+       ASSERT(si->rev >= 3);
+
+       si->bar0 = sd->bar0;
+
+       /* Rev < 10 PciSpiHost has 2 BARs:
+        *    BAR0 = PCI Core Registers
+        *    BAR1 = PciSpiHost Registers (all other cores on backplane)
+        *
+        * Rev 10 and up use a different PCI core which only has a single
+        * BAR0 which contains the PciSpiHost Registers.
+        */
+       if (si->rev < 10) {
+               si->pciregs = (spih_pciregs_t *)spi_reg_map(osh,
+                                                             (uintptr)si->bar0,
+                                                             sizeof(spih_pciregs_t));
+               sd_err(("Mapped PCI Core regs to BAR0 at %p\n", si->pciregs));
+
+               si->bar1 = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR1, 4);
+               si->regs = (spih_regs_t *)spi_reg_map(osh,
+                                                       (uintptr)si->bar1,
+                                                       sizeof(spih_regs_t));
+               sd_err(("Mapped SPI Controller regs to BAR1 at %p\n", si->regs));
+       } else {
+               si->regs = (spih_regs_t *)spi_reg_map(osh,
+                                                             (uintptr)si->bar0,
+                                                             sizeof(spih_regs_t));
+               sd_err(("Mapped SPI Controller regs to BAR0 at %p\n", si->regs));
+               si->pciregs = NULL;
+       }
+       /* Enable SPI Controller, 16.67MHz SPI Clock */
+       SPIPCI_WREG(osh, &si->regs->spih_ctrl, 0x000000d1);
+
+       /* Set extended feature register to defaults */
+       SPIPCI_WREG(osh, &si->regs->spih_ext, 0x00000000);
+
+       /* Set GPIO CS# High (de-asserted) */
+       SPIPCI_WREG(osh, &si->regs->spih_gpio_data, SPIH_CS);
+
+       /* set GPIO[0] to output for CS# */
+       /* set GPIO[1] to output for power control */
+       /* set GPIO[2] to input for card detect */
+       SPIPCI_WREG(osh, &si->regs->spih_gpio_ctrl, (SPIH_CS | SPIH_SLOT_POWER));
+
+       /* Clear out the Read FIFO in case there is any stuff left in there from a previous run. */
+       while ((SPIPCI_RREG(osh, &si->regs->spih_stat) & SPIH_RFEMPTY) == 0) {
+               SPIPCI_RREG(osh, &si->regs->spih_data);
+       }
+
+       /* Wait for power to stabilize to the SDIO Card (100msec was insufficient) */
+       OSL_DELAY(250000);
+
+       /* Check card detect on FPGA Revision >= 4 */
+       if (si->rev >= 4) {
+               if (SPIPCI_RREG(osh, &si->regs->spih_gpio_data) & SPIH_CARD_DETECT) {
+                       sd_err(("%s: no card detected in SD slot\n", __FUNCTION__));
+                       spi_reg_unmap(osh, (uintptr)si->regs, sizeof(spih_regs_t));
+                       if (si->pciregs) {
+                               spi_reg_unmap(osh, (uintptr)si->pciregs, sizeof(spih_pciregs_t));
+                       }
+                       MFREE(osh, si, sizeof(spih_info_t));
+                       return FALSE;
+               }
+       }
+
+       /* Interrupts are level sensitive */
+       SPIPCI_WREG(osh, &si->regs->spih_int_edge, 0x80000000);
+
+       /* Interrupts are active low. */
+       SPIPCI_WREG(osh, &si->regs->spih_int_pol, 0x40000004);
+
+       /* Enable interrupts through PCI Core. */
+       if (si->pciregs) {
+               SPIPCI_WREG(osh, &si->pciregs->ICR, PCI_INT_PROP_EN);
+       }
+
+       sd_trace(("%s: exit\n", __FUNCTION__));
+       return TRUE;
+}
+
+/* Detach and return PCI-SPI Hardware to unconfigured state */
+bool
+spi_hw_detach(sdioh_info_t *sd)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+       spih_pciregs_t *pciregs = si->pciregs;
+
+       sd_trace(("%s: enter\n", __FUNCTION__));
+
+       SPIPCI_WREG(osh, &regs->spih_ctrl, 0x00000010);
+       SPIPCI_WREG(osh, &regs->spih_gpio_ctrl, 0x00000000);    /* Disable GPIO for CS# */
+       SPIPCI_WREG(osh, &regs->spih_int_mask, 0x00000000);     /* Clear Intmask */
+       SPIPCI_WREG(osh, &regs->spih_hex_disp, 0x0000DEAF);
+       SPIPCI_WREG(osh, &regs->spih_int_edge, 0x00000000);
+       SPIPCI_WREG(osh, &regs->spih_int_pol, 0x00000000);
+       SPIPCI_WREG(osh, &regs->spih_hex_disp, 0x0000DEAD);
+
+       /* Disable interrupts through PCI Core. */
+       if (si->pciregs) {
+               SPIPCI_WREG(osh, &pciregs->ICR, 0x00000000);
+               spi_reg_unmap(osh, (uintptr)pciregs, sizeof(spih_pciregs_t));
+       }
+       spi_reg_unmap(osh, (uintptr)regs, sizeof(spih_regs_t));
+
+       MFREE(osh, si, sizeof(spih_info_t));
+
+       sd->controller = NULL;
+
+       sd_trace(("%s: exit\n", __FUNCTION__));
+       return TRUE;
+}
+
+/* Switch between internal (PCI) and external clock oscillator */
+static bool
+sdspi_switch_clock(sdioh_info_t *sd, bool ext_clk)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+
+       /* Switch to desired clock, and reset the PLL. */
+       SPIPCI_WREG(osh, &regs->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0);
+
+       SPINWAIT(((SPIPCI_RREG(osh, &regs->spih_pll_status) & SPIH_PLL_LOCKED)
+                 != SPIH_PLL_LOCKED), 1000);
+       if ((SPIPCI_RREG(osh, &regs->spih_pll_status) & SPIH_PLL_LOCKED) != SPIH_PLL_LOCKED) {
+               sd_err(("%s: timeout waiting for PLL to lock\n", __FUNCTION__));
+               return (FALSE);
+       }
+       return (TRUE);
+
+}
+
+/* Configure PCI-SPI Host Controller's SPI Clock rate as a divisor into the
+ * base clock rate.  The base clock is either the PCI Clock (33MHz) or the
+ * external clock oscillator at U17 on the PciSpiHost.
+ */
+bool
+spi_start_clock(sdioh_info_t *sd, uint16 div)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+       uint32 t, espr, disp;
+       uint32 disp_xtal_freq;
+       bool    ext_clock = FALSE;
+       char disp_string[5];
+
+       if (div > 2048) {
+               sd_err(("%s: divisor %d too large; using max of 2048\n", __FUNCTION__, div));
+               div = 2048;
+       } else if (div & (div - 1)) {   /* Not a power of 2? */
+               /* Round up to a power of 2 */
+               while ((div + 1) & div)
+                       div |= div >> 1;
+               div++;
+       }
+
+       /* For FPGA Rev >= 5, the use of an external clock oscillator is supported.
+        * If the oscillator is populated, use it to provide the SPI base clock,
+        * otherwise, default to the PCI clock as the SPI base clock.
+        */
+       if (si->rev >= 5) {
+               uint32 clk_tick;
+               /* Enable the External Clock Oscillator as PLL clock source. */
+               if (!sdspi_switch_clock(sd, TRUE)) {
+                       sd_err(("%s: error switching to external clock\n", __FUNCTION__));
+               }
+
+               /* Check to make sure the external clock is running.  If not, then it
+                * is not populated on the card, so we will default to the PCI clock.
+                */
+               clk_tick = SPIPCI_RREG(osh, &regs->spih_clk_count);
+               if (clk_tick == SPIPCI_RREG(osh, &regs->spih_clk_count)) {
+
+                       /* Switch back to the PCI clock as the clock source. */
+                       if (!sdspi_switch_clock(sd, FALSE)) {
+                               sd_err(("%s: error switching to external clock\n", __FUNCTION__));
+                       }
+               } else {
+                       ext_clock = TRUE;
+               }
+       }
+
+       /* Hack to allow hot-swapping oscillators:
+        * 1. Force PCI clock as clock source, using sd_divisor of 0.
+        * 2. Swap oscillator
+        * 3. Set desired sd_divisor (will switch to external oscillator as clock source.
+        */
+       if (div == 0) {
+               ext_clock = FALSE;
+               div = 2;
+
+               /* Select PCI clock as the clock source. */
+               if (!sdspi_switch_clock(sd, FALSE)) {
+                       sd_err(("%s: error switching to external clock\n", __FUNCTION__));
+               }
+
+               sd_err(("%s: Ok to hot-swap oscillators.\n", __FUNCTION__));
+       }
+
+       /* If using the external oscillator, read the clock frequency from the controller
+        * The value read is in units of 10000Hz, and it's not a nice round number because
+        * it is calculated by the FPGA.  So to make up for that, we round it off.
+        */
+       if (ext_clock == TRUE) {
+               uint32 xtal_freq;
+
+               OSL_DELAY(1000);
+               xtal_freq = SPIPCI_RREG(osh, &regs->spih_xtal_freq) * 10000;
+
+               sd_info(("%s: Oscillator is %dHz\n", __FUNCTION__, xtal_freq));
+
+
+               disp_xtal_freq = xtal_freq / 10000;
+
+               /* Round it off to a nice number. */
+               if ((disp_xtal_freq % 100) > 50) {
+                       disp_xtal_freq += 100;
+               }
+
+               disp_xtal_freq = (disp_xtal_freq / 100) * 100;
+       } else {
+               sd_err(("%s: no external oscillator installed, using PCI clock.\n", __FUNCTION__));
+               disp_xtal_freq = 3333;
+       }
+
+       /* Convert the SPI Clock frequency to BCD format. */
+       sprintf(disp_string, "%04d", disp_xtal_freq / div);
+
+       disp  = (disp_string[0] - '0') << 12;
+       disp |= (disp_string[1] - '0') << 8;
+       disp |= (disp_string[2] - '0') << 4;
+       disp |= (disp_string[3] - '0');
+
+       /* Select the correct ESPR register value based on the divisor. */
+       switch (div) {
+               case 1:         espr = 0x0; break;
+               case 2:         espr = 0x1; break;
+               case 4:         espr = 0x2; break;
+               case 8:         espr = 0x5; break;
+               case 16:        espr = 0x3; break;
+               case 32:        espr = 0x4; break;
+               case 64:        espr = 0x6; break;
+               case 128:       espr = 0x7; break;
+               case 256:       espr = 0x8; break;
+               case 512:       espr = 0x9; break;
+               case 1024:      espr = 0xa; break;
+               case 2048:      espr = 0xb; break;
+               default:        espr = 0x0; ASSERT(0); break;
+       }
+
+       t = SPIPCI_RREG(osh, &regs->spih_ctrl);
+       t &= ~3;
+       t |= espr & 3;
+       SPIPCI_WREG(osh, &regs->spih_ctrl, t);
+
+       t = SPIPCI_RREG(osh, &regs->spih_ext);
+       t &= ~3;
+       t |= (espr >> 2) & 3;
+       SPIPCI_WREG(osh, &regs->spih_ext, t);
+
+       SPIPCI_WREG(osh, &regs->spih_hex_disp, disp);
+
+       /* For Rev 8, writing to the PLL_CTRL register resets
+        * the PLL, and it can re-acquire in 200uS.  For
+        * Rev 7 and older, we use a software delay to allow
+        * the PLL to re-acquire, which takes more than 2mS.
+        */
+       if (si->rev < 8) {
+               /* Wait for clock to settle. */
+               OSL_DELAY(5000);
+       }
+
+       sd_info(("%s: SPI_CTRL=0x%08x SPI_EXT=0x%08x\n",
+                __FUNCTION__,
+                SPIPCI_RREG(osh, &regs->spih_ctrl),
+                SPIPCI_RREG(osh, &regs->spih_ext)));
+
+       return TRUE;
+}
+
+/* Configure PCI-SPI Host Controller High-Speed Clocking mode setting */
+bool
+spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+
+       if (si->rev >= 10) {
+               if (hsmode) {
+                       SPIPCI_ORREG(osh, &regs->spih_ext, 0x10);
+               } else {
+                       SPIPCI_ANDREG(osh, &regs->spih_ext, ~0x10);
+               }
+       }
+
+       return TRUE;
+}
+
+/* Disable device interrupt */
+void
+spi_devintr_off(sdioh_info_t *sd)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+
+       sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
+       if (sd->use_client_ints) {
+               sd->intmask &= ~SPIH_DEV_INTR;
+               SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);    /* Clear Intmask */
+       }
+}
+
+/* Enable device interrupt */
+void
+spi_devintr_on(sdioh_info_t *sd)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+
+       ASSERT(sd->lockcount == 0);
+       sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
+       if (sd->use_client_ints) {
+               if (SPIPCI_RREG(osh, &regs->spih_ctrl) & 0x02) {
+                       /* Ack in case one was pending but is no longer... */
+                       SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_DEV_INTR);
+               }
+               sd->intmask |= SPIH_DEV_INTR;
+               /* Set device intr in Intmask */
+               SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
+       }
+}
+
+/* Check to see if an interrupt belongs to the PCI-SPI Host or a SPI Device */
+bool
+spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+       bool ours = FALSE;
+
+       uint32 raw_int, cur_int;
+       ASSERT(sd);
+
+       if (is_dev_intr)
+               *is_dev_intr = FALSE;
+       raw_int = SPIPCI_RREG(osh, &regs->spih_int_status);
+       cur_int = raw_int & sd->intmask;
+       if (cur_int & SPIH_DEV_INTR) {
+               if (sd->client_intr_enabled && sd->use_client_ints) {
+                       sd->intrcount++;
+                       ASSERT(sd->intr_handler);
+                       ASSERT(sd->intr_handler_arg);
+                       (sd->intr_handler)(sd->intr_handler_arg);
+                       if (is_dev_intr)
+                               *is_dev_intr = TRUE;
+               } else {
+                       sd_trace(("%s: Not ready for intr: enabled %d, handler 0x%p\n",
+                               __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
+               }
+               SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_DEV_INTR);
+               SPIPCI_RREG(osh, &regs->spih_int_status);
+               ours = TRUE;
+       } else if (cur_int & SPIH_CTLR_INTR) {
+               /* Interrupt is from SPI FIFO... just clear and ack it... */
+               sd_trace(("%s: SPI CTLR interrupt: raw_int 0x%08x cur_int 0x%08x\n",
+                         __FUNCTION__, raw_int, cur_int));
+
+               /* Clear the interrupt in the SPI_STAT register */
+               SPIPCI_WREG(osh, &regs->spih_stat, 0x00000080);
+
+               /* Ack the interrupt in the interrupt controller */
+               SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_CTLR_INTR);
+               SPIPCI_RREG(osh, &regs->spih_int_status);
+
+               ours = TRUE;
+       } else if (cur_int & SPIH_WFIFO_INTR) {
+               sd_trace(("%s: SPI WR FIFO Empty interrupt: raw_int 0x%08x cur_int 0x%08x\n",
+                         __FUNCTION__, raw_int, cur_int));
+
+               /* Disable the FIFO Empty Interrupt */
+               sd->intmask &= ~SPIH_WFIFO_INTR;
+               SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
+
+               sd->local_intrcount++;
+               sd->got_hcint = TRUE;
+               ours = TRUE;
+       } else {
+               /* Not an error: can share interrupts... */
+               sd_trace(("%s: Not my interrupt: raw_int 0x%08x cur_int 0x%08x\n",
+                         __FUNCTION__, raw_int, cur_int));
+               ours = FALSE;
+       }
+
+       return ours;
+}
+
+static void
+hexdump(char *pfx, unsigned char *msg, int msglen)
+{
+       int i, col;
+       char buf[80];
+
+       ASSERT(strlen(pfx) + 49 <= sizeof(buf));
+
+       col = 0;
+
+       for (i = 0; i < msglen; i++, col++) {
+               if (col % 16 == 0)
+                       strcpy(buf, pfx);
+               sprintf(buf + strlen(buf), "%02x", msg[i]);
+               if ((col + 1) % 16 == 0)
+                       printf("%s\n", buf);
+               else
+                       sprintf(buf + strlen(buf), " ");
+       }
+
+       if (col % 16 != 0)
+               printf("%s\n", buf);
+}
+
+/* Send/Receive an SPI Packet */
+void
+spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+       uint32 count;
+       uint32 spi_data_out;
+       uint32 spi_data_in;
+       bool yield;
+
+       sd_trace(("%s: enter\n", __FUNCTION__));
+
+       if (bcmpcispi_dump) {
+               printf("SENDRECV(len=%d)\n", msglen);
+               hexdump(" OUT: ", msg_out, msglen);
+       }
+
+#ifdef BCMSDYIELD
+       /* Only yield the CPU and wait for interrupt on Rev 8 and newer FPGA images. */
+       yield = ((msglen > 500) && (si->rev >= 8));
+#else
+       yield = FALSE;
+#endif /* BCMSDYIELD */
+
+       ASSERT(msglen % 4 == 0);
+
+
+       SPIPCI_ANDREG(osh, &regs->spih_gpio_data, ~SPIH_CS);    /* Set GPIO CS# Low (asserted) */
+
+       for (count = 0; count < (uint32)msglen/4; count++) {
+               spi_data_out = ((uint32)((uint32 *)msg_out)[count]);
+               SPIPCI_WREG(osh, &regs->spih_data, spi_data_out);
+       }
+
+#ifdef BCMSDYIELD
+       if (yield) {
+               /* Ack the interrupt in the interrupt controller */
+               SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_WFIFO_INTR);
+               SPIPCI_RREG(osh, &regs->spih_int_status);
+
+               /* Enable the FIFO Empty Interrupt */
+               sd->intmask |= SPIH_WFIFO_INTR;
+               sd->got_hcint = FALSE;
+               SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
+
+       }
+#endif /* BCMSDYIELD */
+
+       /* Wait for write fifo to empty... */
+       SPIPCI_ANDREG(osh, &regs->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */
+
+       if (yield) {
+               ASSERT((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0);
+       }
+
+       spi_waitbits(sd, yield);
+       SPIPCI_ORREG(osh, &regs->spih_gpio_data, 0x00000020);   /* Set GPIO 5 High (de-asserted) */
+
+       for (count = 0; count < (uint32)msglen/4; count++) {
+               spi_data_in = SPIPCI_RREG(osh, &regs->spih_data);
+               ((uint32 *)msg_in)[count] = spi_data_in;
+       }
+
+       /* Set GPIO CS# High (de-asserted) */
+       SPIPCI_ORREG(osh, &regs->spih_gpio_data, SPIH_CS);
+
+       if (bcmpcispi_dump) {
+               hexdump(" IN : ", msg_in, msglen);
+       }
+}
+
+void
+spi_spinbits(sdioh_info_t *sd)
+{
+       spih_info_t *si = (spih_info_t *)sd->controller;
+       osl_t *osh = si->osh;
+       spih_regs_t *regs = si->regs;
+       uint spin_count; /* Spin loop bound check */
+
+       spin_count = 0;
+       while ((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0) {
+               if (spin_count > SPI_SPIN_BOUND) {
+                       ASSERT(FALSE); /* Spin bound exceeded */
+               }
+               spin_count++;
+       }
+       spin_count = 0;
+       /* Wait for SPI Transfer state machine to return to IDLE state.
+        * The state bits are only implemented in Rev >= 5 FPGA.  These
+        * bits are hardwired to 00 for Rev < 5, so this check doesn't cause
+        * any problems.
+        */
+       while ((SPIPCI_RREG(osh, &regs->spih_stat) & SPIH_STATE_MASK) != 0) {
+               if (spin_count > SPI_SPIN_BOUND) {
+                       ASSERT(FALSE);
+               }
+               spin_count++;
+       }
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh.c b/bcm4329/src/bcmsdio/sys/bcmsdh.c
new file mode 100644 (file)
index 0000000..68295ba
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ *  BCMSDH interface glue
+ *  implement bcmsdh API for SDIOH driver
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdh.c,v 1.35.2.1.4.8.6.8 2009/06/09 00:58:13 Exp $
+ */
+/* ****************** BCMSDH Interface Functions *************************** */
+
+#include <typedefs.h>
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <osl.h>
+
+#include <bcmsdh.h>    /* BRCM API for SDIO clients (such as wl, dhd) */
+#include <bcmsdbus.h>  /* common SDIO/controller interface */
+#include <sbsdio.h>    /* BRCM sdio device core */
+
+#include <sdio.h>      /* sdio spec */
+
+const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
+
+
+struct bcmsdh_info
+{
+       bool    init_success;   /* underlying driver successfully attached */
+       void    *sdioh;         /* handler for sdioh */
+       uint32  vendevid;       /* Target Vendor and Device ID on SD bus */
+       osl_t   *osh;
+       bool    regfail;        /* Save status of last reg_read/reg_write call */
+       uint32  sbwad;          /* Save backplane window address */
+};
+/* local copy of bcm sd handler */
+bcmsdh_info_t * l_bcmsdh = NULL;
+
+bcmsdh_info_t *
+bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
+{
+       bcmsdh_info_t *bcmsdh;
+
+       if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
+               BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
+               return NULL;
+       }
+       bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
+
+       /* save the handler locally */
+       l_bcmsdh = bcmsdh;
+
+       if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) {
+               bcmsdh_detach(osh, bcmsdh);
+               return NULL;
+       }
+
+       bcmsdh->osh = osh;
+       bcmsdh->init_success = TRUE;
+
+       *regsva = (uint32 *)SI_ENUM_BASE;
+
+       /* Report the BAR, to fix if needed */
+       bcmsdh->sbwad = SI_ENUM_BASE;
+       return bcmsdh;
+}
+
+int
+bcmsdh_detach(osl_t *osh, void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       ASSERT(bcmsdh);
+
+       if (bcmsdh->sdioh) {
+               sdioh_detach(osh, bcmsdh->sdioh);
+               bcmsdh->sdioh = NULL;
+       }
+
+       if (bcmsdh) {
+               MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
+       }
+
+       l_bcmsdh = NULL;
+       return 0;
+}
+
+int
+bcmsdh_iovar_op(void *sdh, const char *name,
+                void *params, int plen, void *arg, int len, bool set)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
+}
+
+bool
+bcmsdh_intr_query(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       bool on;
+
+       ASSERT(bcmsdh);
+       status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
+       if (SDIOH_API_SUCCESS(status))
+               return FALSE;
+       else
+               return on;
+}
+
+int
+bcmsdh_intr_enable(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       ASSERT(bcmsdh);
+
+       status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+int
+bcmsdh_intr_disable(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       ASSERT(bcmsdh);
+
+       status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+int
+bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       ASSERT(bcmsdh);
+
+       status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+int
+bcmsdh_intr_dereg(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       ASSERT(bcmsdh);
+
+       status = sdioh_interrupt_deregister(bcmsdh->sdioh);
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+#if defined(DHD_DEBUG)
+bool
+bcmsdh_intr_pending(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       ASSERT(sdh);
+       return sdioh_interrupt_pending(bcmsdh->sdioh);
+}
+#endif
+
+
+int
+bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
+{
+       ASSERT(sdh);
+
+       /* don't support yet */
+       return BCME_UNSUPPORTED;
+}
+
+uint8
+bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint8 data = 0;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
+       if (err)
+               *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
+                   fnc_num, addr, data));
+
+       return data;
+}
+
+void
+bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
+       if (err)
+               *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
+                   fnc_num, addr, data));
+}
+
+uint32
+bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint32 data = 0;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num,
+                                   addr, &data, 4);
+
+       if (err)
+               *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__,
+                   fnc_num, addr, data));
+
+       return data;
+}
+
+void
+bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num,
+                                   addr, &data, 4);
+
+       if (err)
+               *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num,
+                    addr, data));
+}
+
+
+int
+bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+
+       uint8 *tmp_buf, *tmp_ptr;
+       uint8 *ptr;
+       bool ascii = func & ~0xf;
+       func &= 0xf;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+       ASSERT(cis);
+       ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
+
+       status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
+
+       if (ascii) {
+               /* Move binary bits to tmp and format them into the provided buffer. */
+               if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) {
+                       BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__));
+                       return BCME_NOMEM;
+               }
+               bcopy(cis, tmp_buf, length);
+               for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) {
+                       ptr += sprintf((char*)ptr, "%.2x ", *tmp_ptr & 0xff);
+                       if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
+                               ptr += sprintf((char *)ptr, "\n");
+               }
+               MFREE(bcmsdh->osh, tmp_buf, length);
+       }
+
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+
+static int
+bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address)
+{
+       int err = 0;
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
+                        (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
+       if (!err)
+               bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
+                                (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
+       if (!err)
+               bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
+                                (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
+
+
+       return err;
+}
+
+uint32
+bcmsdh_reg_read(void *sdh, uint32 addr, uint size)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint32 word;
+       uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+
+       BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr));
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       if (bar0 != bcmsdh->sbwad) {
+               if (bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0))
+                       return 0xFFFFFFFF;
+
+               bcmsdh->sbwad = bar0;
+       }
+
+       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+       if (size == 4)
+               addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+       status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
+               SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
+
+       bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
+
+       BCMSDH_INFO(("uint32data = 0x%x\n", word));
+
+       /* if ok, return appropriately masked word */
+       if (SDIOH_API_SUCCESS(status)) {
+               switch (size) {
+                       case sizeof(uint8):
+                               return (word & 0xff);
+                       case sizeof(uint16):
+                               return (word & 0xffff);
+                       case sizeof(uint32):
+                               return word;
+                       default:
+                               bcmsdh->regfail = TRUE;
+
+               }
+       }
+
+       /* otherwise, bad sdio access or invalid size */
+       BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size));
+       return 0xFFFFFFFF;
+}
+
+uint32
+bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+       int err = 0;
+
+       BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
+                    __FUNCTION__, addr, size*8, data));
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       ASSERT(bcmsdh->init_success);
+
+       if (bar0 != bcmsdh->sbwad) {
+               if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
+                       return err;
+
+               bcmsdh->sbwad = bar0;
+       }
+
+       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+       if (size == 4)
+               addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+       status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1,
+                                   addr, &data, size);
+       bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
+
+       if (SDIOH_API_SUCCESS(status))
+               return 0;
+
+       BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
+                     __FUNCTION__, data, addr, size));
+       return 0xFFFFFFFF;
+}
+
+bool
+bcmsdh_regfail(void *sdh)
+{
+       return ((bcmsdh_info_t *)sdh)->regfail;
+}
+
+int
+bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
+                uint8 *buf, uint nbytes, void *pkt,
+                bcmsdh_cmplt_fn_t complete, void *handle)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint incr_fix;
+       uint width;
+       uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+       int err = 0;
+
+       ASSERT(bcmsdh);
+       ASSERT(bcmsdh->init_success);
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
+                    __FUNCTION__, fn, addr, nbytes));
+
+       /* Async not implemented yet */
+       ASSERT(!(flags & SDIO_REQ_ASYNC));
+       if (flags & SDIO_REQ_ASYNC)
+               return BCME_UNSUPPORTED;
+
+       if (bar0 != bcmsdh->sbwad) {
+               if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
+                       return err;
+
+               bcmsdh->sbwad = bar0;
+       }
+
+       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+       incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+       if (width == 4)
+               addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+       status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
+                                     SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
+
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
+}
+
+int
+bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
+                uint8 *buf, uint nbytes, void *pkt,
+                bcmsdh_cmplt_fn_t complete, void *handle)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+       uint incr_fix;
+       uint width;
+       uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+       int err = 0;
+
+       ASSERT(bcmsdh);
+       ASSERT(bcmsdh->init_success);
+
+       BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
+                   __FUNCTION__, fn, addr, nbytes));
+
+       /* Async not implemented yet */
+       ASSERT(!(flags & SDIO_REQ_ASYNC));
+       if (flags & SDIO_REQ_ASYNC)
+               return BCME_UNSUPPORTED;
+
+       if (bar0 != bcmsdh->sbwad) {
+               if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
+                       return err;
+
+               bcmsdh->sbwad = bar0;
+       }
+
+       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+       incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+       if (width == 4)
+               addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+       status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
+                                     SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
+
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+int
+bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       SDIOH_API_RC status;
+
+       ASSERT(bcmsdh);
+       ASSERT(bcmsdh->init_success);
+       ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
+
+       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+       addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+       status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
+                                     (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
+                                     addr, 4, nbytes, buf, NULL);
+
+       return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+int
+bcmsdh_abort(void *sdh, uint fn)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       return sdioh_abort(bcmsdh->sdioh, fn);
+}
+
+int
+bcmsdh_start(void *sdh, int stage)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       return sdioh_start(bcmsdh->sdioh, stage);
+}
+
+int
+bcmsdh_stop(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       return sdioh_stop(bcmsdh->sdioh);
+}
+
+
+int
+bcmsdh_query_device(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+       bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
+       return (bcmsdh->vendevid);
+}
+
+uint
+bcmsdh_query_iofnum(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       return (sdioh_query_iofnum(bcmsdh->sdioh));
+}
+
+int
+bcmsdh_reset(bcmsdh_info_t *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       return sdioh_sdio_reset(bcmsdh->sdioh);
+}
+
+void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
+{
+       ASSERT(sdh);
+       return sdh->sdioh;
+}
+
+/* Function to pass device-status bits to DHD. */
+uint32
+bcmsdh_get_dstatus(void *sdh)
+{
+       return 0;
+}
+uint32
+bcmsdh_cur_sbwad(void *sdh)
+{
+       bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+
+       if (!bcmsdh)
+               bcmsdh = l_bcmsdh;
+
+       return (bcmsdh->sbwad);
+}
+
+void
+bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
+{
+       return;
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
new file mode 100644 (file)
index 0000000..81b15b6
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * SDIO access interface for drivers - linux specific (pci only)
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdh_linux.c,v 1.42.10.10.2.6 2009/04/10 19:13:00 Exp $
+ */
+
+/**
+ * @file bcmsdh_linux.c
+ */
+
+#define __UNDEF_NO_VERSION__
+
+#include <typedefs.h>
+#include <linuxver.h>
+
+#include <linux/pci.h>
+#include <linux/completion.h>
+
+#include <osl.h>
+#include <pcicfg.h>
+#include <bcmdefs.h>
+#include <bcmdevs.h>
+
+#if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270)
+#if !defined(BCMPLATFORM_BUS)
+#define BCMPLATFORM_BUS
+#endif /* !defined(BCMPLATFORM_BUS) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
+#include <linux/platform_device.h>
+#endif /* KERNEL_VERSION(2, 6, 19) */
+#endif /* CONFIG_MACH_SANDGATE2G || CONFIG_MACH_LOGICPD_PXA270 */
+
+/**
+ * SDIO Host Controller info
+ */
+typedef struct bcmsdh_hc bcmsdh_hc_t;
+
+struct bcmsdh_hc {
+       bcmsdh_hc_t *next;
+#ifdef BCMPLATFORM_BUS
+       struct device *dev;                     /* platform device handle */
+#else
+       struct pci_dev *dev;            /* pci device handle */
+#endif /* BCMPLATFORM_BUS */
+       osl_t *osh;
+       void *regs;                     /* SDIO Host Controller address */
+       bcmsdh_info_t *sdh;             /* SDIO Host Controller handle */
+       void *ch;
+};
+static bcmsdh_hc_t *sdhcinfo = NULL;
+
+/* driver info, initialized when bcmsdh_register is called */
+static bcmsdh_driver_t drvinfo = {NULL, NULL};
+
+/* debugging macros */
+#define SDLX_MSG(x)
+
+/**
+ * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
+ */
+bool
+bcmsdh_chipmatch(uint16 vendor, uint16 device)
+{
+       /* Add other vendors and devices as required */
+
+#ifdef BCMSDIOH_STD
+       /* Check for Arasan host controller */
+       if (vendor == VENDOR_SI_IMAGE) {
+               return (TRUE);
+       }
+       /* Check for BRCM 27XX Standard host controller */
+       if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
+               return (TRUE);
+       }
+       /* Check for BRCM Standard host controller */
+       if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
+               return (TRUE);
+       }
+       /* Check for TI PCIxx21 Standard host controller */
+       if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
+               return (TRUE);
+       }
+       if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
+               return (TRUE);
+       }
+       /* Ricoh R5C822 Standard SDIO Host */
+       if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
+               return (TRUE);
+       }
+       /* JMicron Standard SDIO Host */
+       if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
+               return (TRUE);
+       }
+
+#endif /* BCMSDIOH_STD */
+#ifdef BCMSDIOH_SPI
+       /* This is the PciSpiHost. */
+       if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
+               printf("Found PCI SPI Host Controller\n");
+               return (TRUE);
+       }
+
+#endif /* BCMSDIOH_SPI */
+
+       return (FALSE);
+}
+
+#if defined(BCMPLATFORM_BUS)
+#if defined(BCMLXSDMMC)
+/* forward declarations */
+int bcmsdh_probe(struct device *dev);
+int bcmsdh_remove(struct device *dev);
+
+EXPORT_SYMBOL(bcmsdh_probe);
+EXPORT_SYMBOL(bcmsdh_remove);
+
+#else
+/* forward declarations */
+static int __devinit bcmsdh_probe(struct device *dev);
+static int __devexit bcmsdh_remove(struct device *dev);
+#endif /* BCMLXSDMMC */
+
+#ifndef BCMLXSDMMC
+static struct device_driver bcmsdh_driver = {
+       .name           = "pxa2xx-mci",
+       .bus            = &platform_bus_type,
+       .probe          = bcmsdh_probe,
+       .remove         = bcmsdh_remove,
+       .suspend        = NULL,
+       .resume         = NULL,
+       };
+#endif /* BCMLXSDMMC */
+
+#ifndef BCMLXSDMMC
+static
+#endif /* BCMLXSDMMC */
+int bcmsdh_probe(struct device *dev)
+{
+       osl_t *osh = NULL;
+       bcmsdh_hc_t *sdhc = NULL;
+       ulong regs = 0;
+       bcmsdh_info_t *sdh = NULL;
+#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
+       struct platform_device *pdev;
+       struct resource *r;
+#endif /* BCMLXSDMMC */
+       int irq = 0;
+       uint32 vendevid;
+
+#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
+       pdev = to_platform_device(dev);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!r || irq == NO_IRQ)
+               return -ENXIO;
+#endif /* BCMLXSDMMC */
+
+       /* allocate SDIO Host Controller state info */
+       if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
+               SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
+               goto err;
+       }
+       if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
+               SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
+                       __FUNCTION__,
+                       MALLOCED(osh)));
+               goto err;
+       }
+       bzero(sdhc, sizeof(bcmsdh_hc_t));
+       sdhc->osh = osh;
+
+       sdhc->dev = (void *)dev;
+
+#ifdef BCMLXSDMMC
+       if (!(sdh = bcmsdh_attach(osh, (void *)0,
+                                 (void **)&regs, irq))) {
+               SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+               goto err;
+       }
+#else
+       if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
+                                 (void **)&regs, irq))) {
+               SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+               goto err;
+       }
+#endif /* BCMLXSDMMC */
+       sdhc->sdh = sdh;
+
+       /* Read the vendor/device ID from the CIS */
+       vendevid = bcmsdh_query_device(sdh);
+
+       /* try to attach to the target device */
+       if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
+                                        (vendevid & 0xFFFF), 0, 0, 0, 0,
+                                       (void *)regs, NULL, sdh))) {
+               SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
+               goto err;
+       }
+
+       /* chain SDIO Host Controller info together */
+       sdhc->next = sdhcinfo;
+       sdhcinfo = sdhc;
+
+       return 0;
+
+       /* error handling */
+err:
+       if (sdhc) {
+               if (sdhc->sdh)
+                       bcmsdh_detach(sdhc->osh, sdhc->sdh);
+               MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
+       }
+       if (osh)
+               osl_detach(osh);
+       return -ENODEV;
+}
+
+#ifndef BCMLXSDMMC
+static
+#endif /* BCMLXSDMMC */
+int bcmsdh_remove(struct device *dev)
+{
+       bcmsdh_hc_t *sdhc, *prev;
+       osl_t *osh;
+
+       /* find the SDIO Host Controller state for this pdev and take it out from the list */
+       for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
+               if (sdhc->dev == (void *)dev) {
+                       if (prev)
+                               prev->next = sdhc->next;
+                       else
+                               sdhcinfo = NULL;
+                       break;
+               }
+               prev = sdhc;
+       }
+       if (!sdhc) {
+               SDLX_MSG(("%s: failed\n", __FUNCTION__));
+               return 0;
+       }
+
+       drvinfo.detach(sdhc->ch);
+
+       bcmsdh_detach(sdhc->osh, sdhc->sdh);
+
+       /* release SDIO Host Controller info */
+       osh = sdhc->osh;
+       MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
+       osl_detach(osh);
+
+#if !defined(BCMLXSDMMC)
+       dev_set_drvdata(dev, NULL);
+#endif /* !defined(BCMLXSDMMC) */
+
+       return 0;
+}
+
+#else /* BCMPLATFORM_BUS */
+
+#if !defined(BCMLXSDMMC)
+/* forward declarations for PCI probe and remove functions. */
+static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
+
+/**
+ * pci id table
+ */
+static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
+       { vendor: PCI_ANY_ID,
+       device: PCI_ANY_ID,
+       subvendor: PCI_ANY_ID,
+       subdevice: PCI_ANY_ID,
+       class: 0,
+       class_mask: 0,
+       driver_data: 0,
+       },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
+
+/**
+ * SDIO Host Controller pci driver info
+ */
+static struct pci_driver bcmsdh_pci_driver = {
+       node:           {},
+       name:           "bcmsdh",
+       id_table:       bcmsdh_pci_devid,
+       probe:          bcmsdh_pci_probe,
+       remove:         bcmsdh_pci_remove,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+       save_state:     NULL,
+#endif
+       suspend:        NULL,
+       resume:         NULL,
+       };
+
+
+/**
+ * Detect supported SDIO Host Controller and attach if found.
+ *
+ * Determine if the device described by pdev is a supported SDIO Host
+ * Controller.  If so, attach to it and attach to the target device.
+ */
+static int __devinit
+bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       osl_t *osh = NULL;
+       bcmsdh_hc_t *sdhc = NULL;
+       ulong regs;
+       bcmsdh_info_t *sdh = NULL;
+       int rc;
+
+       if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
+           (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
+               uint32 config_reg;
+
+               SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
+               if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
+                       SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
+                       goto err;
+               }
+
+               config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
+
+               /*
+                * Set MMC_SD_DIS bit in FlashMedia Controller.
+                * Disbling the SD/MMC Controller in the FlashMedia Controller
+                * allows the Standard SD Host Controller to take over control
+                * of the SD Slot.
+                */
+               config_reg |= 0x02;
+               OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
+               osl_detach(osh);
+       }
+       /* match this pci device with what we support */
+       /* we can't solely rely on this to believe it is our SDIO Host Controller! */
+       if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
+               return -ENODEV;
+       }
+
+       /* this is a pci device we might support */
+       SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
+               __FUNCTION__,
+               pdev->bus->number, PCI_SLOT(pdev->devfn),
+               PCI_FUNC(pdev->devfn), pdev->irq));
+
+       /* use bcmsdh_query_device() to get the vendor ID of the target device so
+        * it will eventually appear in the Broadcom string on the console
+        */
+
+       /* allocate SDIO Host Controller state info */
+       if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
+               SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
+               goto err;
+       }
+       if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
+               SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
+                       __FUNCTION__,
+                       MALLOCED(osh)));
+               goto err;
+       }
+       bzero(sdhc, sizeof(bcmsdh_hc_t));
+       sdhc->osh = osh;
+
+       sdhc->dev = pdev;
+
+       /* map to address where host can access */
+       pci_set_master(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__));
+               goto err;
+       }
+       if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
+                                 (void **)&regs, pdev->irq))) {
+               SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+               goto err;
+       }
+
+       sdhc->sdh = sdh;
+
+       /* try to attach to the target device */
+       if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
+                                       bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
+                                       (void *)regs, NULL, sdh))) {
+               SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
+               goto err;
+       }
+
+       /* chain SDIO Host Controller info together */
+       sdhc->next = sdhcinfo;
+       sdhcinfo = sdhc;
+
+       return 0;
+
+       /* error handling */
+err:
+       if (sdhc->sdh)
+               bcmsdh_detach(sdhc->osh, sdhc->sdh);
+       if (sdhc)
+               MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
+       if (osh)
+               osl_detach(osh);
+       return -ENODEV;
+}
+
+
+/**
+ * Detach from target devices and SDIO Host Controller
+ */
+static void __devexit
+bcmsdh_pci_remove(struct pci_dev *pdev)
+{
+       bcmsdh_hc_t *sdhc, *prev;
+       osl_t *osh;
+
+       /* find the SDIO Host Controller state for this pdev and take it out from the list */
+       for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
+               if (sdhc->dev == pdev) {
+                       if (prev)
+                               prev->next = sdhc->next;
+                       else
+                               sdhcinfo = NULL;
+                       break;
+               }
+               prev = sdhc;
+       }
+       if (!sdhc)
+               return;
+
+       drvinfo.detach(sdhc->ch);
+
+       bcmsdh_detach(sdhc->osh, sdhc->sdh);
+
+       /* release SDIO Host Controller info */
+       osh = sdhc->osh;
+       MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
+       osl_detach(osh);
+}
+#endif /* BCMLXSDMMC */
+#endif /* BCMPLATFORM_BUS */
+
+extern int sdio_function_init(void);
+
+int
+bcmsdh_register(bcmsdh_driver_t *driver)
+{
+       int error = 0;
+
+       drvinfo = *driver;
+
+#if defined(BCMPLATFORM_BUS)
+#if defined(BCMLXSDMMC)
+       SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
+       error = sdio_function_init();
+#else
+       SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
+       error = driver_register(&bcmsdh_driver);
+#endif /* defined(BCMLXSDMMC) */
+       return error;
+#endif /* defined(BCMPLATFORM_BUS) */
+
+#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+       if (!(error = pci_module_init(&bcmsdh_pci_driver)))
+               return 0;
+#else
+       if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
+               return 0;
+#endif
+
+       SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
+#endif /* BCMPLATFORM_BUS */
+
+       return error;
+}
+
+extern void sdio_function_cleanup(void);
+
+void
+bcmsdh_unregister(void)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+       if (bcmsdh_pci_driver.node.next)
+#endif
+
+#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
+               driver_unregister(&bcmsdh_driver);
+#endif
+#if defined(BCMLXSDMMC)
+       sdio_function_cleanup();
+#endif /* BCMLXSDMMC */
+#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
+               pci_unregister_driver(&bcmsdh_pci_driver);
+#endif /* BCMPLATFORM_BUS */
+}
+
+/* Module parameters specific to each host-controller driver */
+
+extern uint sd_msglevel;       /* Debug message level */
+module_param(sd_msglevel, uint, 0);
+
+extern uint sd_power;  /* 0 = SD Power OFF, 1 = SD Power ON. */
+module_param(sd_power, uint, 0);
+
+extern uint sd_clock;  /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
+module_param(sd_clock, uint, 0);
+
+extern uint sd_divisor;        /* Divisor (-1 means external clock) */
+module_param(sd_divisor, uint, 0);
+
+extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
+module_param(sd_sdmode, uint, 0);
+
+extern uint sd_hiok;   /* Ok to use hi-speed mode */
+module_param(sd_hiok, uint, 0);
+
+extern uint sd_f2_blocksize;
+module_param(sd_f2_blocksize, int, 0);
+
+
+#ifdef BCMSDH_MODULE
+EXPORT_SYMBOL(bcmsdh_attach);
+EXPORT_SYMBOL(bcmsdh_detach);
+EXPORT_SYMBOL(bcmsdh_intr_query);
+EXPORT_SYMBOL(bcmsdh_intr_enable);
+EXPORT_SYMBOL(bcmsdh_intr_disable);
+EXPORT_SYMBOL(bcmsdh_intr_reg);
+EXPORT_SYMBOL(bcmsdh_intr_dereg);
+
+#if defined(DHD_DEBUG)
+EXPORT_SYMBOL(bcmsdh_intr_pending);
+#endif
+
+EXPORT_SYMBOL(bcmsdh_devremove_reg);
+EXPORT_SYMBOL(bcmsdh_cfg_read);
+EXPORT_SYMBOL(bcmsdh_cfg_write);
+EXPORT_SYMBOL(bcmsdh_cis_read);
+EXPORT_SYMBOL(bcmsdh_reg_read);
+EXPORT_SYMBOL(bcmsdh_reg_write);
+EXPORT_SYMBOL(bcmsdh_regfail);
+EXPORT_SYMBOL(bcmsdh_send_buf);
+EXPORT_SYMBOL(bcmsdh_recv_buf);
+
+EXPORT_SYMBOL(bcmsdh_rwdata);
+EXPORT_SYMBOL(bcmsdh_abort);
+EXPORT_SYMBOL(bcmsdh_query_device);
+EXPORT_SYMBOL(bcmsdh_query_iofnum);
+EXPORT_SYMBOL(bcmsdh_iovar_op);
+EXPORT_SYMBOL(bcmsdh_register);
+EXPORT_SYMBOL(bcmsdh_unregister);
+EXPORT_SYMBOL(bcmsdh_chipmatch);
+EXPORT_SYMBOL(bcmsdh_reset);
+
+EXPORT_SYMBOL(bcmsdh_get_dstatus);
+EXPORT_SYMBOL(bcmsdh_cfg_read_word);
+EXPORT_SYMBOL(bcmsdh_cfg_write_word);
+EXPORT_SYMBOL(bcmsdh_cur_sbwad);
+EXPORT_SYMBOL(bcmsdh_chipinfo);
+
+#endif /* BCMSDH_MODULE */
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c
new file mode 100644 (file)
index 0000000..9f75672
--- /dev/null
@@ -0,0 +1,1155 @@
+/*
+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.19 2009/06/09 00:57:07 Exp $
+ */
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <sdio.h>      /* SDIO Device and Protocol Specs */
+#include <sdioh.h>     /* SDIO Host Controller Specification */
+#include <bcmsdbus.h>  /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>   /* ioctl/iovars */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "bcmsdh_sdmmc.h"
+
+#ifndef BCMSDH_MODULE
+extern int sdio_function_init(void);
+extern void sdio_function_cleanup(void);
+#endif /* BCMSDH_MODULE */
+
+static void IRQHandler(struct sdio_func *func);
+static void IRQHandlerF2(struct sdio_func *func);
+static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
+extern int sdio_reset_comm(struct mmc_card *card);
+
+extern PBCMSDH_SDMMC_INSTANCE gInstance;
+
+uint sd_sdmode = SDIOH_MODE_SD4;       /* Use SD4 mode by default */
+uint sd_f2_blocksize = 512;            /* Default blocksize */
+
+uint sd_divisor = 2;                   /* Default 48MHz/2 = 24MHz */
+
+uint sd_power = 1;             /* Default to SD Slot powered ON */
+uint sd_clock = 1;             /* Default to SD Clock turned ON */
+uint sd_hiok = FALSE;  /* Don't use hi-speed mode by default */
+uint sd_msglevel = 0x01;
+uint sd_use_dma = TRUE;
+
+#define DMA_ALIGN_MASK 0x03
+
+int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
+
+
+void SDIO_CLAIM_HOST(uint32 func)
+{
+       sdio_claim_host(gInstance->func[func]);
+}
+
+void SDIO_RELEASE_HOST(uint32 func)
+{
+       sdio_release_host(gInstance->func[func]);
+}
+
+static int
+sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
+{
+       int err_ret;
+       uint32 fbraddr;
+       uint8 func;
+
+       sd_trace(("%s\n", __FUNCTION__));
+
+       /* Get the Card's common CIS address */
+       sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
+       sd->func_cis_ptr[0] = sd->com_cis_ptr;
+       sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
+
+       /* Get the Card's function CIS (for each function) */
+       for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
+            func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
+               sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
+               sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
+                        __FUNCTION__, func, sd->func_cis_ptr[func]));
+       }
+
+       sd->func_cis_ptr[0] = sd->com_cis_ptr;
+       sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
+
+       /* Enable Function 1 */
+       gInstance->host_claimed = 0;
+       SDIO_CLAIM_HOST(1);
+       err_ret = sdio_enable_func(gInstance->func[1]);
+       SDIO_RELEASE_HOST(1);
+       if (err_ret) {
+               sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
+       }
+
+       return FALSE;
+}
+
+/*
+ *     Public entry points & extern's
+ */
+extern sdioh_info_t *
+sdioh_attach(osl_t *osh, void *bar0, uint irq)
+{
+       sdioh_info_t *sd;
+       int err_ret;
+
+       sd_trace(("%s\n", __FUNCTION__));
+
+       if (gInstance == NULL) {
+               sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
+               return NULL;
+       }
+
+       if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
+               sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
+               return NULL;
+       }
+       bzero((char *)sd, sizeof(sdioh_info_t));
+       sd->osh = osh;
+       if (sdioh_sdmmc_osinit(sd) != 0) {
+               sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return NULL;
+       }
+
+       sd->num_funcs = 2;
+       sd->sd_blockmode = TRUE;
+       sd->use_client_ints = TRUE;
+       sd->client_block_size[0] = 64;
+
+       gInstance->sd = sd;
+
+       /* Claim host controller */
+       SDIO_CLAIM_HOST(1);
+
+       sd->client_block_size[1] = 64;
+       err_ret = sdio_set_block_size(gInstance->func[1], 64);
+       if (err_ret) {
+               sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
+       }
+
+       /* Release host controller F1 */
+       SDIO_RELEASE_HOST(1);
+
+       if (gInstance->func[2]) {
+               /* Claim host controller F2 */
+               SDIO_CLAIM_HOST(2);
+
+               sd->client_block_size[2] = sd_f2_blocksize;
+               err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
+               if (err_ret) {
+                       sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
+                               sd_f2_blocksize));
+               }
+
+               /* Release host controller F2 */
+               SDIO_RELEASE_HOST(2);
+       }
+
+       sdioh_sdmmc_card_enablefuncs(sd);
+
+       sd_trace(("%s: Done\n", __FUNCTION__));
+       return sd;
+}
+
+
+extern SDIOH_API_RC
+sdioh_detach(osl_t *osh, sdioh_info_t *sd)
+{
+       sd_trace(("%s\n", __FUNCTION__));
+
+       if (sd) {
+
+               /* Disable Function 2 */
+               SDIO_CLAIM_HOST(2);
+               sdio_disable_func(gInstance->func[2]);
+               SDIO_RELEASE_HOST(2);
+
+               /* Disable Function 1 */
+               SDIO_CLAIM_HOST(1);
+               sdio_disable_func(gInstance->func[1]);
+               SDIO_RELEASE_HOST(1);
+
+               /* deregister irq */
+               sdioh_sdmmc_osfree(sd);
+
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+       }
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Configure callback to client when we recieve client interrupt */
+extern SDIOH_API_RC
+sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+       if (fn == NULL) {
+               sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
+               return SDIOH_API_RC_FAIL;
+       }
+       sd->intr_handler = fn;
+       sd->intr_handler_arg = argh;
+       sd->intr_handler_valid = TRUE;
+
+       /* register and unmask irq */
+       if (gInstance->func[2]) {
+               SDIO_CLAIM_HOST(2);
+               sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
+               SDIO_RELEASE_HOST(2);
+       }
+
+       if (gInstance->func[1]) {
+               SDIO_CLAIM_HOST(1);
+               sdio_claim_irq(gInstance->func[1], IRQHandler);
+               SDIO_RELEASE_HOST(1);
+       }
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_deregister(sdioh_info_t *sd)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+
+       if (gInstance->func[1]) {
+               /* register and unmask irq */
+               SDIO_CLAIM_HOST(1);
+               sdio_release_irq(gInstance->func[1]);
+               SDIO_RELEASE_HOST(1);
+       }
+
+       if (gInstance->func[2]) {
+               /* Claim host controller F2 */
+               SDIO_CLAIM_HOST(2);
+               sdio_release_irq(gInstance->func[2]);
+               /* Release host controller F2 */
+               SDIO_RELEASE_HOST(2);
+       }
+
+       sd->intr_handler_valid = FALSE;
+       sd->intr_handler = NULL;
+       sd->intr_handler_arg = NULL;
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+       *onoff = sd->client_intr_enabled;
+       return SDIOH_API_RC_SUCCESS;
+}
+
+#if defined(DHD_DEBUG)
+extern bool
+sdioh_interrupt_pending(sdioh_info_t *sd)
+{
+       return (0);
+}
+#endif
+
+uint
+sdioh_query_iofnum(sdioh_info_t *sd)
+{
+       return sd->num_funcs;
+}
+
+/* IOVar table */
+enum {
+       IOV_MSGLEVEL = 1,
+       IOV_BLOCKMODE,
+       IOV_BLOCKSIZE,
+       IOV_DMA,
+       IOV_USEINTS,
+       IOV_NUMINTS,
+       IOV_NUMLOCALINTS,
+       IOV_HOSTREG,
+       IOV_DEVREG,
+       IOV_DIVISOR,
+       IOV_SDMODE,
+       IOV_HISPEED,
+       IOV_HCIREGS,
+       IOV_POWER,
+       IOV_CLOCK,
+       IOV_RXCHAIN
+};
+
+const bcm_iovar_t sdioh_iovars[] = {
+       {"sd_msglevel", IOV_MSGLEVEL,   0,      IOVT_UINT32,    0 },
+       {"sd_blockmode", IOV_BLOCKMODE, 0,      IOVT_BOOL,      0 },
+       {"sd_blocksize", IOV_BLOCKSIZE, 0,      IOVT_UINT32,    0 }, /* ((fn << 16) | size) */
+       {"sd_dma",      IOV_DMA,        0,      IOVT_BOOL,      0 },
+       {"sd_ints",     IOV_USEINTS,    0,      IOVT_BOOL,      0 },
+       {"sd_numints",  IOV_NUMINTS,    0,      IOVT_UINT32,    0 },
+       {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32,   0 },
+       {"sd_hostreg",  IOV_HOSTREG,    0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_devreg",   IOV_DEVREG,     0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_divisor",  IOV_DIVISOR,    0,      IOVT_UINT32,    0 },
+       {"sd_power",    IOV_POWER,      0,      IOVT_UINT32,    0 },
+       {"sd_clock",    IOV_CLOCK,      0,      IOVT_UINT32,    0 },
+       {"sd_mode",     IOV_SDMODE,     0,      IOVT_UINT32,    100},
+       {"sd_highspeed", IOV_HISPEED,   0,      IOVT_UINT32,    0 },
+       {"sd_rxchain",  IOV_RXCHAIN,    0,      IOVT_BOOL,      0 },
+       {NULL, 0, 0, 0, 0 }
+};
+
+int
+sdioh_iovar_op(sdioh_info_t *si, const char *name,
+                           void *params, int plen, void *arg, int len, bool set)
+{
+       const bcm_iovar_t *vi = NULL;
+       int bcmerror = 0;
+       int val_size;
+       int32 int_val = 0;
+       bool bool_val;
+       uint32 actionid;
+
+       ASSERT(name);
+       ASSERT(len >= 0);
+
+       /* Get must have return space; Set does not take qualifiers */
+       ASSERT(set || (arg && len));
+       ASSERT(!set || (!params && !plen));
+
+       sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
+
+       if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
+               bcmerror = BCME_UNSUPPORTED;
+               goto exit;
+       }
+
+       if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
+               goto exit;
+
+       /* Set up params so get and set can share the convenience variables */
+       if (params == NULL) {
+               params = arg;
+               plen = len;
+       }
+
+       if (vi->type == IOVT_VOID)
+               val_size = 0;
+       else if (vi->type == IOVT_BUFFER)
+               val_size = len;
+       else
+               val_size = sizeof(int);
+
+       if (plen >= (int)sizeof(int_val))
+               bcopy(params, &int_val, sizeof(int_val));
+
+       bool_val = (int_val != 0) ? TRUE : FALSE;
+
+       actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
+       switch (actionid) {
+       case IOV_GVAL(IOV_MSGLEVEL):
+               int_val = (int32)sd_msglevel;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_MSGLEVEL):
+               sd_msglevel = int_val;
+               break;
+
+       case IOV_GVAL(IOV_BLOCKMODE):
+               int_val = (int32)si->sd_blockmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKMODE):
+               si->sd_blockmode = (bool)int_val;
+               /* Haven't figured out how to make non-block mode with DMA */
+               break;
+
+       case IOV_GVAL(IOV_BLOCKSIZE):
+               if ((uint32)int_val > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               int_val = (int32)si->client_block_size[int_val];
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKSIZE):
+       {
+               uint func = ((uint32)int_val >> 16);
+               uint blksize = (uint16)int_val;
+               uint maxsize;
+
+               if (func > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               switch (func) {
+               case 0: maxsize = 32; break;
+               case 1: maxsize = BLOCK_SIZE_4318; break;
+               case 2: maxsize = BLOCK_SIZE_4328; break;
+               default: maxsize = 0;
+               }
+               if (blksize > maxsize) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               if (!blksize) {
+                       blksize = maxsize;
+               }
+
+               /* Now set it */
+               si->client_block_size[func] = blksize;
+
+               break;
+       }
+
+       case IOV_GVAL(IOV_RXCHAIN):
+               int_val = FALSE;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_DMA):
+               int_val = (int32)si->sd_use_dma;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DMA):
+               si->sd_use_dma = (bool)int_val;
+               break;
+
+       case IOV_GVAL(IOV_USEINTS):
+               int_val = (int32)si->use_client_ints;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_USEINTS):
+               si->use_client_ints = (bool)int_val;
+               if (si->use_client_ints)
+                       si->intmask |= CLIENT_INTR;
+               else
+                       si->intmask &= ~CLIENT_INTR;
+
+               break;
+
+       case IOV_GVAL(IOV_DIVISOR):
+               int_val = (uint32)sd_divisor;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DIVISOR):
+               sd_divisor = int_val;
+               break;
+
+       case IOV_GVAL(IOV_POWER):
+               int_val = (uint32)sd_power;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_POWER):
+               sd_power = int_val;
+               break;
+
+       case IOV_GVAL(IOV_CLOCK):
+               int_val = (uint32)sd_clock;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_CLOCK):
+               sd_clock = int_val;
+               break;
+
+       case IOV_GVAL(IOV_SDMODE):
+               int_val = (uint32)sd_sdmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_SDMODE):
+               sd_sdmode = int_val;
+               break;
+
+       case IOV_GVAL(IOV_HISPEED):
+               int_val = (uint32)sd_hiok;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_HISPEED):
+               sd_hiok = int_val;
+               break;
+
+       case IOV_GVAL(IOV_NUMINTS):
+               int_val = (int32)si->intrcount;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_NUMLOCALINTS):
+               int_val = (int32)0;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_HOSTREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+
+               if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+                       sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
+                                 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+                                 sd_ptr->offset));
+               if (sd_ptr->offset & 1)
+                       int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
+               else if (sd_ptr->offset & 2)
+                       int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
+               else
+                       int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
+
+               bcopy(&int_val, arg, sizeof(int_val));
+               break;
+       }
+
+       case IOV_SVAL(IOV_HOSTREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+
+               if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+                       sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
+                                 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+                                 sd_ptr->offset));
+               break;
+       }
+
+       case IOV_GVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data = 0;
+
+               if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+
+               int_val = (int)data;
+               bcopy(&int_val, arg, sizeof(int_val));
+               break;
+       }
+
+       case IOV_SVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data = (uint8)sd_ptr->value;
+
+               if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+               break;
+       }
+
+       default:
+               bcmerror = BCME_UNSUPPORTED;
+               break;
+       }
+exit:
+
+       return bcmerror;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       SDIOH_API_RC status;
+       /* No lock needed since sdioh_request_byte does locking */
+       status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
+       return status;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       /* No lock needed since sdioh_request_byte does locking */
+       SDIOH_API_RC status;
+       status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
+       return status;
+}
+
+static int
+sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
+{
+       /* read 24 bits and return valid 17 bit addr */
+       int i;
+       uint32 scratch, regdata;
+       uint8 *ptr = (uint8 *)&scratch;
+       for (i = 0; i < 3; i++) {
+               if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
+                       sd_err(("%s: Can't read!\n", __FUNCTION__));
+
+               *ptr++ = (uint8) regdata;
+               regaddr++;
+       }
+
+       /* Only the lower 17-bits are valid */
+       scratch = ltoh32(scratch);
+       scratch &= 0x0001FFFF;
+       return (scratch);
+}
+
+extern SDIOH_API_RC
+sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
+{
+       uint32 count;
+       int offset;
+       uint32 foo;
+       uint8 *cis = cisd;
+
+       sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
+
+       if (!sd->func_cis_ptr[func]) {
+               bzero(cis, length);
+               sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
+               return SDIOH_API_RC_FAIL;
+       }
+
+       sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
+
+       for (count = 0; count < length; count++) {
+               offset =  sd->func_cis_ptr[func] + count;
+               if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
+                       sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
+                       return SDIOH_API_RC_FAIL;
+               }
+
+               *cis = (uint8)(foo & 0xff);
+               cis++;
+       }
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
+{
+       int err_ret;
+
+       sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
+
+       if(rw) { /* CMD52 Write */
+               if (func == 0) {
+                       /* Can only directly write to some F0 registers.  Handle F2 enable
+                        * as a special case.
+                        */
+                       if (regaddr == SDIOD_CCCR_IOEN) {
+                               if (gInstance->func[2]) {
+                                       SDIO_CLAIM_HOST(2);
+                                       if (*byte & SDIO_FUNC_ENABLE_2) {
+                                               /* Enable Function 2 */
+                                               err_ret = sdio_enable_func(gInstance->func[2]);
+                                               if (err_ret) {
+                                                       sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
+                                                               err_ret));
+                                               }
+                                       } else {
+                                               /* Disable Function 2 */
+                                               err_ret = sdio_disable_func(gInstance->func[2]);
+                                               if (err_ret) {
+                                                       sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
+                                                               err_ret));
+                                               }
+                                       }
+                                       SDIO_RELEASE_HOST(2);
+                               }
+                       } else if (regaddr < 0xF0) {
+                               sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
+                       } else {
+                               /* Claim host controller, perform F0 write, and release */
+                               SDIO_CLAIM_HOST(func);
+                               sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
+                               SDIO_RELEASE_HOST(func);
+                       }
+               } else {
+                       /* Claim host controller, perform Fn write, and release */
+                       SDIO_CLAIM_HOST(func);
+                       sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
+                       SDIO_RELEASE_HOST(func);
+               }
+       } else { /* CMD52 Read */
+               /* Claim host controller, perform Fn read, and release */
+               SDIO_CLAIM_HOST(func);
+
+               if (func == 0) {
+                       *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
+               } else {
+                       *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
+               }
+
+               SDIO_RELEASE_HOST(func);
+       }
+
+       if (err_ret) {
+               sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+                                       rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
+       }
+
+       return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+extern SDIOH_API_RC
+sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
+                                   uint32 *word, uint nbytes)
+{
+       int err_ret;
+
+       if (func == 0) {
+               sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
+               return SDIOH_API_RC_FAIL;
+       }
+
+       sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+                __FUNCTION__, cmd_type, rw, func, addr, nbytes));
+
+       /* Claim host controller */
+       SDIO_CLAIM_HOST(func);
+
+       if(rw) { /* CMD52 Write */
+               if (nbytes == 4) {
+                       sdio_writel(gInstance->func[func], *word, addr, &err_ret);
+               } else if (nbytes == 2) {
+                       sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
+               } else {
+                       sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
+               }
+       } else { /* CMD52 Read */
+               if (nbytes == 4) {
+                       *word = sdio_readl(gInstance->func[func], addr, &err_ret);
+               } else if (nbytes == 2) {
+                       *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
+               } else {
+                       sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
+               }
+       }
+
+       /* Release host controller */
+       SDIO_RELEASE_HOST(func);
+
+       if (err_ret) {
+               sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
+                                       rw ? "Write" : "Read", err_ret));
+       }
+
+       return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+static SDIOH_API_RC
+sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
+                     uint addr, void *pkt)
+{
+       bool fifo = (fix_inc == SDIOH_DATA_FIX);
+       uint32  SGCount = 0;
+       int err_ret = 0;
+
+       void *pnext;
+
+       sd_trace(("%s: Enter\n", __FUNCTION__));
+
+       ASSERT(pkt);
+
+       /* Claim host controller */
+       SDIO_CLAIM_HOST(func);
+       for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+               uint pkt_len = PKTLEN(sd->osh, pnext);
+               pkt_len += 3;
+               pkt_len &= 0xFFFFFFFC;
+
+#ifdef CONFIG_MMC_MSM7X00A
+               if ((pkt_len % 64) == 32) {
+                       sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
+                       pkt_len += 32;
+               }
+#endif /* CONFIG_MMC_MSM7X00A */
+               /* Make sure the packet is aligned properly. If it isn't, then this
+                * is the fault of sdioh_request_buffer() which is supposed to give
+                * us something we can work with.
+                */
+               ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
+
+               if ((write) && (!fifo)) {
+                       err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
+                               ((uint8*)PKTDATA(sd->osh, pnext)),
+                               pkt_len);
+               } else if (write) {
+                       err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
+                               ((uint8*)PKTDATA(sd->osh, pnext)),
+                               pkt_len);
+               } else if (fifo) {
+                       err_ret = sdio_readsb(gInstance->func[func],
+                               ((uint8*)PKTDATA(sd->osh, pnext)),
+                               addr,
+                               pkt_len);
+               } else {
+                       err_ret = sdio_memcpy_fromio(gInstance->func[func],
+                               ((uint8*)PKTDATA(sd->osh, pnext)),
+                               addr,
+                               pkt_len);
+               }
+
+               if (err_ret) {
+                       sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
+                               __FUNCTION__,
+                               (write) ? "TX" : "RX",
+                               pnext, SGCount, addr, pkt_len, err_ret));
+               } else {
+                       sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+                               __FUNCTION__,
+                               (write) ? "TX" : "RX",
+                               pnext, SGCount, addr, pkt_len));
+               }
+
+               if (!fifo) {
+                       addr += pkt_len;
+               }
+               SGCount ++;
+
+       }
+
+       /* Release host controller */
+       SDIO_RELEASE_HOST(func);
+
+       sd_trace(("%s: Exit\n", __FUNCTION__));
+       return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+
+/*
+ * This function takes a buffer or packet, and fixes everything up so that in the
+ * end, a DMA-able packet is created.
+ *
+ * A buffer does not have an associated packet pointer, and may or may not be aligned.
+ * A packet may consist of a single packet, or a packet chain.  If it is a packet chain,
+ * then all the packets in the chain must be properly aligned.  If the packet data is not
+ * aligned, then there may only be one packet, and in this case, it is copied to a new
+ * aligned packet.
+ *
+ */
+extern SDIOH_API_RC
+sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
+                     uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
+{
+       SDIOH_API_RC Status;
+       void *mypkt = NULL;
+
+       sd_trace(("%s: Enter\n", __FUNCTION__));
+
+       /* Case 1: we don't have a packet. */
+       if (pkt == NULL) {
+               sd_data(("%s: Creating new %s Packet, len=%d\n",
+                        __FUNCTION__, write ? "TX" : "RX", buflen_u));
+               if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
+                       sd_err(("%s: PKTGET failed: len %d\n",
+                                  __FUNCTION__, buflen_u));
+                       return SDIOH_API_RC_FAIL;
+               }
+
+               /* For a write, copy the buffer data into the packet. */
+               if (write) {
+                       bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
+               }
+
+               Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
+
+               /* For a read, copy the packet data back to the buffer. */
+               if (!write) {
+                       bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
+               }
+
+               PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
+       } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
+               /* Case 2: We have a packet, but it is unaligned. */
+
+               /* In this case, we cannot have a chain. */
+               ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
+
+               sd_data(("%s: Creating aligned %s Packet, len=%d\n",
+                        __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
+               if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
+                       sd_err(("%s: PKTGET failed: len %d\n",
+                                  __FUNCTION__, PKTLEN(sd->osh, pkt)));
+                       return SDIOH_API_RC_FAIL;
+               }
+
+               /* For a write, copy the buffer data into the packet. */
+               if (write) {
+                       bcopy(PKTDATA(sd->osh, pkt),
+                             PKTDATA(sd->osh, mypkt),
+                             PKTLEN(sd->osh, pkt));
+               }
+
+               Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
+
+               /* For a read, copy the packet data back to the buffer. */
+               if (!write) {
+                       bcopy(PKTDATA(sd->osh, mypkt),
+                             PKTDATA(sd->osh, pkt),
+                             PKTLEN(sd->osh, mypkt));
+               }
+
+               PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
+       } else { /* case 3: We have a packet and it is aligned. */
+               sd_data(("%s: Aligned %s Packet, direct DMA\n",
+                        __FUNCTION__, write ? "Tx" : "Rx"));
+               Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
+       }
+
+       return (Status);
+}
+
+extern int
+sdioh_abort(sdioh_info_t *sd, uint func)
+{
+       sd_trace(("%s: Enter\n", __FUNCTION__));
+
+
+       sd_trace(("%s: Exit\n", __FUNCTION__));
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Reset and re-initialize the device */
+int sdioh_sdio_reset(sdioh_info_t *si)
+{
+       sd_trace(("%s: Enter\n", __FUNCTION__));
+       sd_trace(("%s: Exit\n", __FUNCTION__));
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Disable device interrupt */
+void
+sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
+{
+       sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
+       sd->intmask &= ~CLIENT_INTR;
+}
+
+/* Enable device interrupt */
+void
+sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
+{
+       sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
+       sd->intmask |= CLIENT_INTR;
+}
+
+/* Read client card reg */
+int
+sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
+{
+
+       if ((func == 0) || (regsize == 1)) {
+               uint8 temp = 0;
+
+               sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
+               *data = temp;
+               *data &= 0xff;
+               sd_data(("%s: byte read data=0x%02x\n",
+                        __FUNCTION__, *data));
+       } else {
+               sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
+               if (regsize == 2)
+                       *data &= 0xffff;
+
+               sd_data(("%s: word read data=0x%08x\n",
+                        __FUNCTION__, *data));
+       }
+
+       return SUCCESS;
+}
+
+/* bcmsdh_sdmmc interrupt handler */
+static void IRQHandler(struct sdio_func *func)
+{
+       sdioh_info_t *sd;
+
+       sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
+       sd = gInstance->sd;
+
+       ASSERT(sd != NULL);
+       sdio_release_host(gInstance->func[0]);
+       gInstance->host_claimed = 1;
+       if (sd->use_client_ints) {
+               sd->intrcount++;
+               ASSERT(sd->intr_handler);
+               ASSERT(sd->intr_handler_arg);
+               (sd->intr_handler)(sd->intr_handler_arg);
+       } else {
+               sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
+
+               sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
+                       __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
+       }
+       gInstance->host_claimed = 0;
+
+       sdio_claim_host(gInstance->func[0]);
+}
+
+/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
+static void IRQHandlerF2(struct sdio_func *func)
+{
+       sdioh_info_t *sd;
+
+       sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
+
+       sd = gInstance->sd;
+
+       ASSERT(sd != NULL);
+}
+
+#ifdef NOTUSED
+/* Write client card reg */
+static int
+sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
+{
+
+       if ((func == 0) || (regsize == 1)) {
+               uint8 temp;
+
+               temp = data & 0xff;
+               sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
+               sd_data(("%s: byte write data=0x%02x\n",
+                        __FUNCTION__, data));
+       } else {
+               if (regsize == 2)
+                       data &= 0xffff;
+
+               sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
+
+               sd_data(("%s: word write data=0x%08x\n",
+                        __FUNCTION__, data));
+       }
+
+       return SUCCESS;
+}
+#endif /* NOTUSED */
+
+int
+sdioh_start(sdioh_info_t *si, int stage)
+{
+       int ret;
+       sdioh_info_t *sd = gInstance->sd;
+
+       /* Need to do this stages as we can't enable the interrupt till
+               downloading of the firmware is complete, other wise polling
+               sdio access will come in way
+       */
+       if (gInstance->func[0]) {
+                       if (stage == 0) {
+               /* Since the power to the chip is killed, we will have
+                       re enumerate the device again. Set the block size
+                       and enable the fucntion 1 for in preparation for
+                       downloading the code
+               */
+               /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
+                  2.6.27. The implementation prior to that is buggy, and needs broadcom's
+                  patch for it
+               */
+               if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
+                       sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+               else {
+                       sd->num_funcs = 2;
+                       sd->sd_blockmode = TRUE;
+                       sd->use_client_ints = TRUE;
+                       sd->client_block_size[0] = 64;
+
+                       /* Claim host controller */
+                       sdio_claim_host(gInstance->func[1]);
+
+                       sd->client_block_size[1] = 64;
+                       if (sdio_set_block_size(gInstance->func[1], 64)) {
+                               sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
+                       }
+
+                       /* Release host controller F1 */
+                       sdio_release_host(gInstance->func[1]);
+
+                       if (gInstance->func[2]) {
+                               /* Claim host controller F2 */
+                               sdio_claim_host(gInstance->func[2]);
+
+                               sd->client_block_size[2] = sd_f2_blocksize;
+                               if (sdio_set_block_size(gInstance->func[2],
+                                       sd_f2_blocksize)) {
+                                       sd_err(("bcmsdh_sdmmc: Failed to set F2 "
+                                               "blocksize to %d\n", sd_f2_blocksize));
+                               }
+
+                               /* Release host controller F2 */
+                               sdio_release_host(gInstance->func[2]);
+                       }
+
+                       sdioh_sdmmc_card_enablefuncs(sd);
+                       }
+               } else {
+                       sdio_claim_host(gInstance->func[0]);
+                       sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
+                       sdio_claim_irq(gInstance->func[1], IRQHandler);
+                       sdio_release_host(gInstance->func[0]);
+
+               }
+       }
+       else
+               sd_err(("%s Failed\n", __FUNCTION__));
+
+       return (0);
+}
+
+int
+sdioh_stop(sdioh_info_t *si)
+{
+       /* MSM7201A Android sdio stack has bug with interrupt
+               So internaly within SDIO stack they are polling
+               which cause issue when device is turned off. So
+               unregister interrupt with SDIO stack to stop the
+               polling
+       */
+       if (gInstance->func[0]) {
+               sdio_claim_host(gInstance->func[0]);
+               sdio_release_irq(gInstance->func[1]);
+               sdio_release_irq(gInstance->func[2]);
+               sdio_release_host(gInstance->func[0]);
+       }
+       else
+               sd_err(("%s Failed\n", __FUNCTION__));
+       return (0);
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c
new file mode 100644 (file)
index 0000000..46fe1f9
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdh_sdmmc_linux.c,v 1.1.2.5.6.7 2009/05/22 00:31:44 Exp $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <sdio.h>      /* SDIO Specs */
+#include <bcmsdbus.h>  /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>   /* to get msglevel bit values */
+
+#include <linux/sched.h>       /* request_irq() */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#if !defined(SDIO_VENDOR_ID_BROADCOM)
+#define SDIO_VENDOR_ID_BROADCOM                0x02d0
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
+#define SDIO_DEVICE_ID_BROADCOM_4325   0x0000
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4329)
+#define SDIO_DEVICE_ID_BROADCOM_4329   0x4329
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
+
+#include <bcmsdh_sdmmc.h>
+
+extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
+extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
+
+int sdio_function_init(void);
+void sdio_function_cleanup(void);
+
+#define DESCRIPTION "bcmsdh_sdmmc Driver"
+#define AUTHOR "Broadcom Corporation"
+
+/* module param defaults */
+static int clockoverride = 0;
+
+module_param(clockoverride, int, 0644);
+MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
+
+PBCMSDH_SDMMC_INSTANCE gInstance;
+
+/* Maximum number of bcmsdh_sdmmc devices supported by driver */
+#define BCMSDH_SDMMC_MAX_DEVICES 1
+
+extern int bcmsdh_probe(struct device *dev);
+extern int bcmsdh_remove(struct device *dev);
+struct device sdmmc_dev;
+
+static int bcmsdh_sdmmc_probe(struct sdio_func *func,
+                              const struct sdio_device_id *id)
+{
+       int ret = 0;
+       sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
+       sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class));
+       sd_trace(("sdio_vendor: 0x%04x\n", func->vendor));
+       sd_trace(("sdio_device: 0x%04x\n", func->device));
+       sd_trace(("Function#: 0x%04x\n", func->num));
+
+       if (func->num == 1) {
+               /* Keep a copy of F1's 'func' in F0, just in case... */
+               gInstance->func[0] = func;
+               if(func->device == 0x4) { /* 4318 */
+                       gInstance->func[2] = NULL;
+                       sd_trace(("NIC found, calling bcmsdh_probe...\n"));
+                       bcmsdh_probe(&sdmmc_dev);
+               }
+       }
+
+       gInstance->func[func->num] = func;
+
+       if (func->num == 2) {
+               sd_trace(("F2 found, calling bcmsdh_probe...\n"));
+               bcmsdh_probe(&sdmmc_dev);
+       }
+
+       return ret;
+}
+
+static void bcmsdh_sdmmc_remove(struct sdio_func *func)
+{
+       sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
+       sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
+       sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
+       sd_info(("sdio_device: 0x%04x\n", func->device));
+       sd_info(("Function#: 0x%04x\n", func->num));
+
+       if (func->num == 2) {
+               sd_trace(("F2 found, calling bcmsdh_probe...\n"));
+               bcmsdh_remove(&sdmmc_dev);
+       }
+}
+
+
+/* devices we support, null terminated */
+static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
+       { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE)            },
+       { /* end: all zeroes */                         },
+};
+
+MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
+
+static struct sdio_driver bcmsdh_sdmmc_driver = {
+       .probe          = bcmsdh_sdmmc_probe,
+       .remove         = bcmsdh_sdmmc_remove,
+       .name           = "bcmsdh_sdmmc",
+       .id_table       = bcmsdh_sdmmc_ids,
+       };
+
+struct sdos_info {
+       sdioh_info_t *sd;
+       spinlock_t lock;
+};
+
+
+int
+sdioh_sdmmc_osinit(sdioh_info_t *sd)
+{
+       struct sdos_info *sdos;
+
+       sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
+       sd->sdos_info = (void*)sdos;
+       if (sdos == NULL)
+               return BCME_NOMEM;
+
+       sdos->sd = sd;
+       spin_lock_init(&sdos->lock);
+       return BCME_OK;
+}
+
+void
+sdioh_sdmmc_osfree(sdioh_info_t *sd)
+{
+       struct sdos_info *sdos;
+       ASSERT(sd && sd->sdos_info);
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       MFREE(sd->osh, sdos, sizeof(struct sdos_info));
+}
+
+/* Interrupt enable/disable */
+SDIOH_API_RC
+sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
+{
+       ulong flags;
+       struct sdos_info *sdos;
+
+       sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       ASSERT(sdos);
+
+       if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
+               sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
+               return SDIOH_API_RC_FAIL;
+       }
+
+       /* Ensure atomicity for enable/disable calls */
+       spin_lock_irqsave(&sdos->lock, flags);
+
+       sd->client_intr_enabled = enable;
+       if (enable)
+               sdioh_sdmmc_devintr_on(sd);
+       else
+               sdioh_sdmmc_devintr_off(sd);
+
+       spin_unlock_irqrestore(&sdos->lock, flags);
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+
+#ifdef BCMSDH_MODULE
+static int __init
+bcmsdh_module_init(void)
+{
+       int error = 0;
+       sdio_function_init();
+       return error;
+}
+
+static void __exit
+bcmsdh_module_cleanup(void)
+{
+       sdio_function_cleanup();
+}
+
+module_init(bcmsdh_module_init);
+module_exit(bcmsdh_module_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DESCRIPTION);
+MODULE_AUTHOR(AUTHOR);
+
+#endif /* BCMSDH_MODULE */
+/*
+ * module init
+*/
+int sdio_function_init(void)
+{
+       int error = 0;
+       sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
+
+       gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
+       if (!gInstance)
+               return -ENOMEM;
+
+       error = sdio_register_driver(&bcmsdh_sdmmc_driver);
+       return error;
+}
+
+/*
+ * module cleanup
+*/
+extern int bcmsdh_remove(struct device *dev);
+void sdio_function_cleanup(void)
+{
+       sd_trace(("%s Enter\n", __FUNCTION__));
+
+       sdio_unregister_driver(&bcmsdh_sdmmc_driver);
+
+       if (gInstance)
+               kfree(gInstance);
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdspi.c b/bcm4329/src/bcmsdio/sys/bcmsdspi.c
new file mode 100644 (file)
index 0000000..206f34e
--- /dev/null
@@ -0,0 +1,1595 @@
+/*
+ * Broadcom BCMSDH to SPI Protocol Conversion Layer
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdspi.c,v 1.14.4.2.4.4.6.4 2009/04/13 19:18:36 Exp $
+ */
+
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <siutils.h>
+#include <sdio.h>              /* SDIO Device and Protocol Specs */
+#include <sdioh.h>             /* SDIO Host Controller Specification */
+#include <bcmsdbus.h>          /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>           /* ioctl/iovars */
+
+#include <pcicfg.h>
+
+
+#include <bcmsdspi.h>
+#include <bcmspi.h>
+
+#include <proto/sdspi.h>
+
+#define SD_PAGE 4096
+
+/* Globals */
+
+uint sd_msglevel = SDH_ERROR_VAL;
+uint sd_hiok = FALSE;          /* Use hi-speed mode if available? */
+uint sd_sdmode = SDIOH_MODE_SPI;               /* Use SD4 mode by default */
+uint sd_f2_blocksize = 512;    /* Default blocksize */
+
+uint sd_divisor = 2;           /* Default 33MHz/2 = 16MHz for dongle */
+uint sd_power = 1;             /* Default to SD Slot powered ON */
+uint sd_clock = 1;             /* Default to SD Clock turned ON */
+uint sd_crc = 0;               /* Default to SPI CRC Check turned OFF */
+
+uint sd_toctl = 7;
+
+/* Prototypes */
+static bool sdspi_start_power(sdioh_info_t *sd);
+static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
+static int sdspi_card_enablefuncs(sdioh_info_t *sd);
+static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
+static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
+                           uint32 *data, uint32 datalen);
+static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
+                              int regsize, uint32 *data);
+static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
+                               int regsize, uint32 data);
+static int sdspi_driver_init(sdioh_info_t *sd);
+static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
+static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
+                          uint32 addr, int nbytes, uint32 *data);
+static int sdspi_abort(sdioh_info_t *sd, uint func);
+
+static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
+
+static uint8 sdspi_crc7(unsigned char* p, uint32 len);
+static uint16 sdspi_crc16(unsigned char* p, uint32 len);
+static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc);
+
+/*
+ *  Public entry points & extern's
+ */
+extern sdioh_info_t *
+sdioh_attach(osl_t *osh, void *bar0, uint irq)
+{
+       sdioh_info_t *sd;
+
+       sd_trace(("%s\n", __FUNCTION__));
+       if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
+               sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
+               return NULL;
+       }
+       bzero((char *)sd, sizeof(sdioh_info_t));
+       sd->osh = osh;
+
+       if (spi_osinit(sd) != 0) {
+               sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return NULL;
+       }
+
+       sd->bar0 = (uintptr)bar0;
+       sd->irq = irq;
+       sd->intr_handler = NULL;
+       sd->intr_handler_arg = NULL;
+       sd->intr_handler_valid = FALSE;
+
+       /* Set defaults */
+       sd->sd_blockmode = FALSE;
+       sd->use_client_ints = TRUE;
+       sd->sd_use_dma = FALSE; /* DMA Not supported */
+
+       /* Haven't figured out how to make bytemode work with dma */
+       if (!sd->sd_blockmode)
+               sd->sd_use_dma = 0;
+
+       if (!spi_hw_attach(sd)) {
+               sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
+               spi_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return NULL;
+       }
+
+       if (sdspi_driver_init(sd) != SUCCESS) {
+               if (sdspi_driver_init(sd) != SUCCESS) {
+                       sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__));
+                       spi_hw_detach(sd);
+                       spi_osfree(sd);
+                       MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+                       return (NULL);
+               }
+       }
+
+       if (spi_register_irq(sd, irq) != SUCCESS) {
+               sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
+               spi_hw_detach(sd);
+               spi_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return (NULL);
+       }
+
+       sd_trace(("%s: Done\n", __FUNCTION__));
+       return sd;
+}
+
+extern SDIOH_API_RC
+sdioh_detach(osl_t *osh, sdioh_info_t *sd)
+{
+       sd_trace(("%s\n", __FUNCTION__));
+
+       if (sd) {
+               if (sd->card_init_done)
+                       sdspi_reset(sd, 1, 1);
+
+               sd_info(("%s: detaching from hardware\n", __FUNCTION__));
+               spi_free_irq(sd->irq, sd);
+               spi_hw_detach(sd);
+               spi_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+       }
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Configure callback to client when we recieve client interrupt */
+extern SDIOH_API_RC
+sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+
+       sd->intr_handler = fn;
+       sd->intr_handler_arg = argh;
+       sd->intr_handler_valid = TRUE;
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_deregister(sdioh_info_t *sd)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+
+       sd->intr_handler_valid = FALSE;
+       sd->intr_handler = NULL;
+       sd->intr_handler_arg = NULL;
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+
+       *onoff = sd->client_intr_enabled;
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+#if defined(DHD_DEBUG)
+extern bool
+sdioh_interrupt_pending(sdioh_info_t *sd)
+{
+       return 0;
+}
+#endif
+
+uint
+sdioh_query_iofnum(sdioh_info_t *sd)
+{
+       return sd->num_funcs;
+}
+
+/* IOVar table */
+enum {
+       IOV_MSGLEVEL = 1,
+       IOV_BLOCKMODE,
+       IOV_BLOCKSIZE,
+       IOV_DMA,
+       IOV_USEINTS,
+       IOV_NUMINTS,
+       IOV_NUMLOCALINTS,
+       IOV_HOSTREG,
+       IOV_DEVREG,
+       IOV_DIVISOR,
+       IOV_SDMODE,
+       IOV_HISPEED,
+       IOV_HCIREGS,
+       IOV_POWER,
+       IOV_CLOCK,
+       IOV_CRC
+};
+
+const bcm_iovar_t sdioh_iovars[] = {
+       {"sd_msglevel", IOV_MSGLEVEL,   0,      IOVT_UINT32,    0 },
+       {"sd_blockmode", IOV_BLOCKMODE, 0,      IOVT_BOOL,      0 },
+       {"sd_blocksize", IOV_BLOCKSIZE, 0,      IOVT_UINT32,    0 }, /* ((fn << 16) | size) */
+       {"sd_dma",      IOV_DMA,        0,      IOVT_BOOL,      0 },
+       {"sd_ints",     IOV_USEINTS,    0,      IOVT_BOOL,      0 },
+       {"sd_numints",  IOV_NUMINTS,    0,      IOVT_UINT32,    0 },
+       {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32,   0 },
+       {"sd_hostreg",  IOV_HOSTREG,    0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_devreg",   IOV_DEVREG,     0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_divisor",  IOV_DIVISOR,    0,      IOVT_UINT32,    0 },
+       {"sd_power",    IOV_POWER,      0,      IOVT_UINT32,    0 },
+       {"sd_clock",    IOV_CLOCK,      0,      IOVT_UINT32,    0 },
+       {"sd_crc",      IOV_CRC,        0,      IOVT_UINT32,    0 },
+       {"sd_mode",     IOV_SDMODE,     0,      IOVT_UINT32,    100},
+       {"sd_highspeed",        IOV_HISPEED,    0,      IOVT_UINT32,    0},
+       {NULL, 0, 0, 0, 0 }
+};
+
+int
+sdioh_iovar_op(sdioh_info_t *si, const char *name,
+               void *params, int plen, void *arg, int len, bool set)
+{
+       const bcm_iovar_t *vi = NULL;
+       int bcmerror = 0;
+       int val_size;
+       int32 int_val = 0;
+       bool bool_val;
+       uint32 actionid;
+
+       ASSERT(name);
+       ASSERT(len >= 0);
+
+       /* Get must have return space; Set does not take qualifiers */
+       ASSERT(set || (arg && len));
+       ASSERT(!set || (!params && !plen));
+
+       sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
+
+       if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
+               bcmerror = BCME_UNSUPPORTED;
+               goto exit;
+       }
+
+       if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
+               goto exit;
+
+       /* Set up params so get and set can share the convenience variables */
+       if (params == NULL) {
+               params = arg;
+               plen = len;
+       }
+
+       if (vi->type == IOVT_VOID)
+               val_size = 0;
+       else if (vi->type == IOVT_BUFFER)
+               val_size = len;
+       else
+               val_size = sizeof(int);
+
+       if (plen >= (int)sizeof(int_val))
+               bcopy(params, &int_val, sizeof(int_val));
+
+       bool_val = (int_val != 0) ? TRUE : FALSE;
+
+       actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
+       switch (actionid) {
+       case IOV_GVAL(IOV_MSGLEVEL):
+               int_val = (int32)sd_msglevel;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_MSGLEVEL):
+               sd_msglevel = int_val;
+               break;
+
+       case IOV_GVAL(IOV_BLOCKMODE):
+               int_val = (int32)si->sd_blockmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKMODE):
+               si->sd_blockmode = (bool)int_val;
+               /* Haven't figured out how to make non-block mode with DMA */
+               if (!si->sd_blockmode)
+                       si->sd_use_dma = 0;
+               break;
+
+       case IOV_GVAL(IOV_BLOCKSIZE):
+               if ((uint32)int_val > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               int_val = (int32)si->client_block_size[int_val];
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKSIZE):
+       {
+               uint func = ((uint32)int_val >> 16);
+               uint blksize = (uint16)int_val;
+               uint maxsize;
+
+               if (func > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               switch (func) {
+               case 0: maxsize = 32; break;
+               case 1: maxsize = BLOCK_SIZE_4318; break;
+               case 2: maxsize = BLOCK_SIZE_4328; break;
+               default: maxsize = 0;
+               }
+               if (blksize > maxsize) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               if (!blksize) {
+                       blksize = maxsize;
+               }
+
+               /* Now set it */
+               spi_lock(si);
+               bcmerror = set_client_block_size(si, func, blksize);
+               spi_unlock(si);
+               break;
+       }
+
+       case IOV_GVAL(IOV_DMA):
+               int_val = (int32)si->sd_use_dma;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DMA):
+               si->sd_use_dma = (bool)int_val;
+               break;
+
+       case IOV_GVAL(IOV_USEINTS):
+               int_val = (int32)si->use_client_ints;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_USEINTS):
+               break;
+
+       case IOV_GVAL(IOV_DIVISOR):
+               int_val = (uint32)sd_divisor;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DIVISOR):
+               sd_divisor = int_val;
+               if (!spi_start_clock(si, (uint16)sd_divisor)) {
+                       sd_err(("set clock failed!\n"));
+                       bcmerror = BCME_ERROR;
+               }
+               break;
+
+       case IOV_GVAL(IOV_POWER):
+               int_val = (uint32)sd_power;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_POWER):
+               sd_power = int_val;
+               break;
+
+       case IOV_GVAL(IOV_CLOCK):
+               int_val = (uint32)sd_clock;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_CLOCK):
+               sd_clock = int_val;
+               break;
+
+       case IOV_GVAL(IOV_CRC):
+               int_val = (uint32)sd_crc;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_CRC):
+               /* Apply new setting, but don't change sd_crc until
+                * after the CRC-mode is selected in the device.  This
+                * is required because the software must generate a
+                * correct CRC for the CMD59 in order to be able to
+                * turn OFF the CRC.
+                */
+               sdspi_crc_onoff(si, int_val ? 1 : 0);
+               sd_crc = int_val;
+               break;
+
+       case IOV_GVAL(IOV_SDMODE):
+               int_val = (uint32)sd_sdmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_SDMODE):
+               sd_sdmode = int_val;
+               break;
+
+       case IOV_GVAL(IOV_HISPEED):
+               int_val = (uint32)sd_hiok;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_HISPEED):
+               sd_hiok = int_val;
+
+               if (!sdspi_set_highspeed_mode(si, (bool)sd_hiok)) {
+                       sd_err(("Failed changing highspeed mode to %d.\n", sd_hiok));
+                       bcmerror = BCME_ERROR;
+                       return ERROR;
+               }
+               break;
+
+       case IOV_GVAL(IOV_NUMINTS):
+               int_val = (int32)si->intrcount;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_NUMLOCALINTS):
+               int_val = (int32)si->local_intrcount;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_HOSTREG):
+       {
+               break;
+       }
+
+       case IOV_SVAL(IOV_HOSTREG):
+       {
+               sd_err(("IOV_HOSTREG unsupported\n"));
+               break;
+       }
+
+       case IOV_GVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data;
+
+               if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+
+               int_val = (int)data;
+               bcopy(&int_val, arg, sizeof(int_val));
+               break;
+       }
+
+       case IOV_SVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data = (uint8)sd_ptr->value;
+
+               if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+               break;
+       }
+
+
+       default:
+               bcmerror = BCME_UNSUPPORTED;
+               break;
+       }
+exit:
+
+       return bcmerror;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       SDIOH_API_RC status;
+       /* No lock needed since sdioh_request_byte does locking */
+       status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
+       return status;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       /* No lock needed since sdioh_request_byte does locking */
+       SDIOH_API_RC status;
+       status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
+       return status;
+}
+
+extern SDIOH_API_RC
+sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
+{
+       uint32 count;
+       int offset;
+       uint32 foo;
+       uint8 *cis = cisd;
+
+       sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
+
+       if (!sd->func_cis_ptr[func]) {
+               bzero(cis, length);
+               return SDIOH_API_RC_FAIL;
+       }
+
+       spi_lock(sd);
+       *cis = 0;
+       for (count = 0; count < length; count++) {
+               offset =  sd->func_cis_ptr[func] + count;
+               if (sdspi_card_regread (sd, 0, offset, 1, &foo) < 0) {
+                       sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
+                       spi_unlock(sd);
+                       return SDIOH_API_RC_FAIL;
+               }
+               *cis = (uint8)(foo & 0xff);
+               cis++;
+       }
+       spi_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
+{
+       int status;
+       uint32 cmd_arg;
+       uint32 rsp5;
+
+       spi_lock(sd);
+
+       cmd_arg = 0;
+       cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
+       cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
+       cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte);
+
+       sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x\n", __FUNCTION__, rw, func, regaddr));
+
+       if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
+                                     SDIOH_CMD_52, cmd_arg, NULL, 0)) != SUCCESS) {
+               spi_unlock(sd);
+               return status;
+       }
+
+       sdspi_cmd_getrsp(sd, &rsp5, 1);
+       if (rsp5 != 0x00) {
+               sd_err(("%s: rsp5 flags is 0x%x func=%d\n",
+                       __FUNCTION__, rsp5, func));
+               /* ASSERT(0); */
+               spi_unlock(sd);
+               return SDIOH_API_RC_FAIL;
+       }
+
+       if (rw == SDIOH_READ)
+               *byte = sd->card_rsp_data >> 24;
+
+       spi_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
+                   uint32 *word, uint nbytes)
+{
+       int status;
+
+       spi_lock(sd);
+
+       if (rw == SDIOH_READ)
+               status = sdspi_card_regread(sd, func, addr, nbytes, word);
+       else
+               status = sdspi_card_regwrite(sd, func, addr, nbytes, *word);
+
+       spi_unlock(sd);
+       return (status == SUCCESS ?  SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+extern SDIOH_API_RC
+sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
+                     uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
+{
+       int len;
+       int buflen = (int)buflen_u;
+       bool fifo = (fix_inc == SDIOH_DATA_FIX);
+
+       spi_lock(sd);
+
+       ASSERT(reg_width == 4);
+       ASSERT(buflen_u < (1 << 30));
+       ASSERT(sd->client_block_size[func]);
+
+       sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
+                __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
+                buflen_u, sd->r_cnt, sd->t_cnt, pkt));
+
+       /* Break buffer down into blocksize chunks:
+        * Bytemode: 1 block at a time.
+        */
+       while (buflen > 0) {
+               if (sd->sd_blockmode) {
+                       /* Max xfer is Page size */
+                       len = MIN(SD_PAGE, buflen);
+
+                       /* Round down to a block boundry */
+                       if (buflen > sd->client_block_size[func])
+                               len = (len/sd->client_block_size[func]) *
+                                       sd->client_block_size[func];
+               } else {
+                       /* Byte mode: One block at a time */
+                       len = MIN(sd->client_block_size[func], buflen);
+               }
+
+               if (sdspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
+                       spi_unlock(sd);
+                       return SDIOH_API_RC_FAIL;
+               }
+               buffer += len;
+               buflen -= len;
+               if (!fifo)
+                       addr += len;
+       }
+       spi_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+static int
+sdspi_abort(sdioh_info_t *sd, uint func)
+{
+       uint8 spi_databuf[] = { 0x74, 0x80, 0x00, 0x0C, 0xFF, 0x95, 0xFF, 0xFF,
+                               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+       uint8 spi_rspbuf[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                              0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+       int err = 0;
+
+       sd_err(("Sending SPI Abort to F%d\n", func));
+       spi_databuf[4] = func & 0x7;
+       /* write to function 0, addr 6 (IOABORT) func # in 3 LSBs. */
+       spi_sendrecv(sd, spi_databuf, spi_rspbuf, sizeof(spi_databuf));
+
+       return err;
+}
+
+extern int
+sdioh_abort(sdioh_info_t *sd, uint fnum)
+{
+       int ret;
+
+       spi_lock(sd);
+       ret = sdspi_abort(sd, fnum);
+       spi_unlock(sd);
+
+       return ret;
+}
+
+int
+sdioh_start(sdioh_info_t *sd, int stage)
+{
+       return SUCCESS;
+}
+
+int
+sdioh_stop(sdioh_info_t *sd)
+{
+       return SUCCESS;
+}
+
+
+/*
+ * Private/Static work routines
+ */
+static bool
+sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset)
+{
+       if (!sd)
+               return TRUE;
+
+       spi_lock(sd);
+       /* Reset client card */
+       if (client_reset && (sd->adapter_slot != -1)) {
+               if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS)
+                       sd_err(("%s: Cannot write to card reg 0x%x\n",
+                               __FUNCTION__, SDIOD_CCCR_IOABORT));
+               else
+                       sd->card_rca = 0;
+       }
+
+       /* The host reset is a NOP in the sd-spi case. */
+       if (host_reset) {
+               sd->sd_mode = SDIOH_MODE_SPI;
+       }
+       spi_unlock(sd);
+       return TRUE;
+}
+
+static int
+sdspi_host_init(sdioh_info_t *sd)
+{
+       sdspi_reset(sd, 1, 0);
+
+       /* Default power on mode is SD1 */
+       sd->sd_mode = SDIOH_MODE_SPI;
+       sd->polled_mode = TRUE;
+       sd->host_init_done = TRUE;
+       sd->card_init_done = FALSE;
+       sd->adapter_slot = 1;
+
+       return (SUCCESS);
+}
+
+#define CMD0_RETRIES 3
+#define CMD5_RETRIES 10
+
+static int
+get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp)
+{
+       uint32 rsp5;
+       int retries, status;
+
+       /* First issue a CMD0 to get the card into SPI mode. */
+       for (retries = 0; retries <= CMD0_RETRIES; retries++) {
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
+                                             SDIOH_CMD_0, *cmd_arg, NULL, 0)) != SUCCESS) {
+                       sd_err(("%s: No response to CMD0\n", __FUNCTION__));
+                       continue;
+               }
+
+               sdspi_cmd_getrsp(sd, &rsp5, 1);
+
+               if (GFIELD(rsp5, SPI_RSP_ILL_CMD)) {
+                       printf("%s: Card already initialized (continuing)\n", __FUNCTION__);
+                       break;
+               }
+
+               if (GFIELD(rsp5, SPI_RSP_IDLE)) {
+                       printf("%s: Card in SPI mode\n", __FUNCTION__);
+                       break;
+               }
+       }
+
+       if (retries > CMD0_RETRIES) {
+               sd_err(("%s: Too many retries for CMD0\n", __FUNCTION__));
+               return ERROR;
+       }
+
+       /* Get the Card's Operation Condition. */
+       /* Occasionally the board takes a while to become ready. */
+       for (retries = 0; retries <= CMD5_RETRIES; retries++) {
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
+                                             SDIOH_CMD_5, *cmd_arg, NULL, 0)) != SUCCESS) {
+                       sd_err(("%s: No response to CMD5\n", __FUNCTION__));
+                       continue;
+               }
+
+               printf("CMD5 response data was: 0x%08x\n", sd->card_rsp_data);
+
+               if (GFIELD(sd->card_rsp_data, RSP4_CARD_READY)) {
+                       printf("%s: Card ready\n", __FUNCTION__);
+                       break;
+               }
+       }
+
+       if (retries > CMD5_RETRIES) {
+               sd_err(("%s: Too many retries for CMD5\n", __FUNCTION__));
+               return ERROR;
+       }
+
+       *cmd_rsp = sd->card_rsp_data;
+
+       sdspi_crc_onoff(sd, sd_crc ? 1 : 0);
+
+       return (SUCCESS);
+}
+
+static int
+sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc)
+{
+       uint32 args;
+       int status;
+
+       args = use_crc ? 1 : 0;
+       if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
+                                     SDIOH_CMD_59, args, NULL, 0)) != SUCCESS) {
+               sd_err(("%s: No response to CMD59\n", __FUNCTION__));
+       }
+
+       sd_info(("CMD59 response data was: 0x%08x\n", sd->card_rsp_data));
+
+       sd_err(("SD-SPI CRC turned %s\n", use_crc ? "ON" : "OFF"));
+       return (SUCCESS);
+}
+
+static int
+sdspi_client_init(sdioh_info_t *sd)
+{
+       uint8 fn_ints;
+
+       sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
+
+       /* Start at ~400KHz clock rate for initialization */
+       if (!spi_start_clock(sd, 128)) {
+               sd_err(("spi_start_clock failed\n"));
+               return ERROR;
+       }
+
+       if (!sdspi_start_power(sd)) {
+               sd_err(("sdspi_start_power failed\n"));
+               return ERROR;
+       }
+
+       if (sd->num_funcs == 0) {
+               sd_err(("%s: No IO funcs!\n", __FUNCTION__));
+               return ERROR;
+       }
+
+       sdspi_card_enablefuncs(sd);
+
+       set_client_block_size(sd, 1, BLOCK_SIZE_4318);
+       fn_ints = INTR_CTL_FUNC1_EN;
+
+       if (sd->num_funcs >= 2) {
+               set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */);
+               fn_ints |= INTR_CTL_FUNC2_EN;
+       }
+
+       /* Enable/Disable Client interrupts */
+       /* Turn on here but disable at host controller */
+       if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1,
+                               (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) {
+               sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__));
+               return ERROR;
+       }
+
+       /* Switch to High-speed clocking mode if both host and device support it */
+       sdspi_set_highspeed_mode(sd, (bool)sd_hiok);
+
+       /* After configuring for High-Speed mode, set the desired clock rate. */
+       if (!spi_start_clock(sd, (uint16)sd_divisor)) {
+               sd_err(("spi_start_clock failed\n"));
+               return ERROR;
+       }
+
+       sd->card_init_done = TRUE;
+
+       return SUCCESS;
+}
+
+static int
+sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode)
+{
+       uint32 regdata;
+       int status;
+       bool hsmode;
+
+       if (HSMode == TRUE) {
+
+               sd_err(("Attempting to enable High-Speed mode.\n"));
+
+               if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
+                                                1, &regdata)) != SUCCESS) {
+                       return status;
+               }
+               if (regdata & SDIO_SPEED_SHS) {
+                       sd_err(("Device supports High-Speed mode.\n"));
+
+                       regdata |= SDIO_SPEED_EHS;
+
+                       sd_err(("Writing %08x to Card at %08x\n",
+                                regdata, SDIOD_CCCR_SPEED_CONTROL));
+                       if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
+                                                         1, regdata)) != BCME_OK) {
+                               return status;
+                       }
+
+                       hsmode = 1;
+
+                       sd_err(("High-speed clocking mode enabled.\n"));
+               }
+               else {
+                       sd_err(("Device does not support High-Speed Mode.\n"));
+                       hsmode = 0;
+               }
+       } else {
+               if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
+                                                1, &regdata)) != SUCCESS) {
+                       return status;
+               }
+
+               regdata = ~SDIO_SPEED_EHS;
+
+               sd_err(("Writing %08x to Card at %08x\n",
+                        regdata, SDIOD_CCCR_SPEED_CONTROL));
+               if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
+                                                 1, regdata)) != BCME_OK) {
+                       return status;
+               }
+
+               sd_err(("Low-speed clocking mode enabled.\n"));
+               hsmode = 0;
+       }
+
+       spi_controller_highspeed_mode(sd, hsmode);
+
+       return TRUE;
+}
+
+bool
+sdspi_start_power(sdioh_info_t *sd)
+{
+       uint32 cmd_arg;
+       uint32 cmd_rsp;
+
+       sd_trace(("%s\n", __FUNCTION__));
+
+       /* Get the Card's Operation Condition.  Occasionally the board
+        * takes a while to become ready
+        */
+
+       cmd_arg = 0;
+       if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) {
+               sd_err(("%s: Failed to get OCR; bailing\n", __FUNCTION__));
+               return FALSE;
+       }
+
+       sd_err(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT)));
+       sd_err(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS)));
+       sd_err(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY)));
+       sd_err(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR)));
+
+       /* Verify that the card supports I/O mode */
+       if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) {
+               sd_err(("%s: Card does not support I/O\n", __FUNCTION__));
+               return ERROR;
+       }
+
+       sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS);
+
+       /* Examine voltage: Arasan only supports 3.3 volts,
+        * so look for 3.2-3.3 Volts and also 3.3-3.4 volts.
+        */
+
+       if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) {
+               sd_err(("This client does not support 3.3 volts!\n"));
+               return ERROR;
+       }
+
+
+       return TRUE;
+}
+
+static int
+sdspi_driver_init(sdioh_info_t *sd)
+{
+       sd_trace(("%s\n", __FUNCTION__));
+
+       if ((sdspi_host_init(sd)) != SUCCESS) {
+               return ERROR;
+       }
+
+       if (sdspi_client_init(sd) != SUCCESS) {
+               return ERROR;
+       }
+
+       return SUCCESS;
+}
+
+static int
+sdspi_card_enablefuncs(sdioh_info_t *sd)
+{
+       int status;
+       uint32 regdata;
+       uint32 regaddr, fbraddr;
+       uint8 func;
+       uint8 *ptr;
+
+       sd_trace(("%s\n", __FUNCTION__));
+       /* Get the Card's common CIS address */
+       ptr = (uint8 *) &sd->com_cis_ptr;
+       for (regaddr = SDIOD_CCCR_CISPTR_0; regaddr <= SDIOD_CCCR_CISPTR_2; regaddr++) {
+               if ((status = sdspi_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
+                       return status;
+
+               *ptr++ = (uint8) regdata;
+       }
+
+       /* Only the lower 17-bits are valid */
+       sd->com_cis_ptr &= 0x0001FFFF;
+       sd->func_cis_ptr[0] = sd->com_cis_ptr;
+       sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
+
+       /* Get the Card's function CIS (for each function) */
+       for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
+            func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
+               ptr = (uint8 *) &sd->func_cis_ptr[func];
+               for (regaddr = SDIOD_FBR_CISPTR_0; regaddr <= SDIOD_FBR_CISPTR_2; regaddr++) {
+                       if ((status = sdspi_card_regread (sd, 0, regaddr + fbraddr, 1, &regdata))
+                           != SUCCESS)
+                               return status;
+
+                       *ptr++ = (uint8) regdata;
+               }
+
+               /* Only the lower 17-bits are valid */
+               sd->func_cis_ptr[func] &= 0x0001FFFF;
+               sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
+                        __FUNCTION__, func, sd->func_cis_ptr[func]));
+       }
+
+       sd_info(("%s: write ESCI bit\n", __FUNCTION__));
+       /* Enable continuous SPI interrupt (ESCI bit) */
+       sdspi_card_regwrite(sd, 0, SDIOD_CCCR_BICTRL, 1, 0x60);
+
+       sd_info(("%s: enable f1\n", __FUNCTION__));
+       /* Enable function 1 on the card */
+       regdata = SDIO_FUNC_ENABLE_1;
+       if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS)
+               return status;
+
+       sd_info(("%s: done\n", __FUNCTION__));
+       return SUCCESS;
+}
+
+/* Read client card reg */
+static int
+sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
+{
+       int status;
+       uint32 cmd_arg;
+       uint32 rsp5;
+
+       cmd_arg = 0;
+
+       if ((func == 0) || (regsize == 1)) {
+               cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
+               cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
+               cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ);
+               cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
+               cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0);
+
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
+                   != SUCCESS)
+                       return status;
+
+               sdspi_cmd_getrsp(sd, &rsp5, 1);
+
+               if (rsp5 != 0x00)
+                       sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
+                               __FUNCTION__, rsp5, func));
+
+               *data = sd->card_rsp_data >> 24;
+       } else {
+               cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
+               cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
+               cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
+               cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
+               cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
+               cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
+
+               sd->data_xfer_count = regsize;
+
+               /* sdspi_cmd_issue() returns with the command complete bit
+                * in the ISR already cleared
+                */
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
+                   != SUCCESS)
+                       return status;
+
+               sdspi_cmd_getrsp(sd, &rsp5, 1);
+
+               if (rsp5 != 0x00)
+                       sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
+                               __FUNCTION__, rsp5, func));
+
+               *data = sd->card_rsp_data;
+               if (regsize == 2) {
+                       *data &= 0xffff;
+               }
+
+               sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
+                        __FUNCTION__, func, regaddr, regsize, *data));
+
+
+       }
+
+       return SUCCESS;
+}
+
+/* write a client register */
+static int
+sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
+{
+       int status;
+       uint32 cmd_arg, rsp5, flags;
+
+       cmd_arg = 0;
+
+       if ((func == 0) || (regsize == 1)) {
+               cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
+               cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
+               cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
+               cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
+               cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff);
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
+                   != SUCCESS)
+                       return status;
+
+               sdspi_cmd_getrsp(sd, &rsp5, 1);
+               flags = GFIELD(rsp5, RSP5_FLAGS);
+               if (flags && (flags != 0x10))
+                       sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n",
+                               __FUNCTION__,  flags));
+       }
+       else {
+               cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
+               cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
+               cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
+               cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
+               cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
+               cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
+
+               sd->data_xfer_count = regsize;
+               sd->cmd53_wr_data = data;
+
+               sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
+                        __FUNCTION__, func, regaddr, regsize, data));
+
+               /* sdspi_cmd_issue() returns with the command complete bit
+                * in the ISR already cleared
+                */
+               if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
+                   != SUCCESS)
+                       return status;
+
+               sdspi_cmd_getrsp(sd, &rsp5, 1);
+
+               if (rsp5 != 0x00)
+                       sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
+                               __FUNCTION__,  rsp5));
+
+       }
+       return SUCCESS;
+}
+
+void
+sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */)
+{
+       *rsp_buffer = sd->card_response;
+}
+
+int max_errors = 0;
+
+#define SPI_MAX_PKT_LEN                768
+uint8  spi_databuf[SPI_MAX_PKT_LEN];
+uint8  spi_rspbuf[SPI_MAX_PKT_LEN];
+
+/* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */
+static int
+sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
+                uint32 *data, uint32 datalen)
+{
+       uint32 cmd_reg;
+       uint32 cmd_arg = arg;
+       uint8 cmd_crc = 0x95;           /* correct CRC for CMD0 and don't care for others. */
+       uint16 dat_crc;
+       uint8 cmd52data = 0;
+       uint32 i, j;
+       uint32 spi_datalen = 0;
+       uint32 spi_pre_cmd_pad  = 0;
+       uint32 spi_max_response_pad = 128;
+
+       cmd_reg = 0;
+       cmd_reg = SFIELD(cmd_reg, SPI_DIR, 1);
+       cmd_reg = SFIELD(cmd_reg, SPI_CMD_INDEX, cmd);
+
+       if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {      /* Same for CMD52 and CMD53 */
+               cmd_reg = SFIELD(cmd_reg, SPI_RW, 1);
+       }
+
+       switch (cmd) {
+       case SDIOH_CMD_59:      /* CRC_ON_OFF (SPI Mode Only) - Response R1 */
+               cmd52data = arg & 0x1;
+       case SDIOH_CMD_0:       /* Set Card to Idle State - No Response */
+       case SDIOH_CMD_5:       /* Send Operation condition - Response R4 */
+               sd_trace(("%s: CMD%d\n", __FUNCTION__, cmd));
+               spi_datalen = 44;
+               spi_pre_cmd_pad = 12;
+               spi_max_response_pad = 28;
+               break;
+
+       case SDIOH_CMD_3:       /* Ask card to send RCA - Response R6 */
+       case SDIOH_CMD_7:       /* Select card - Response R1 */
+       case SDIOH_CMD_15:      /* Set card to inactive state - Response None */
+               sd_err(("%s: CMD%d is invalid for SPI Mode.\n", __FUNCTION__, cmd));
+               return ERROR;
+               break;
+
+       case SDIOH_CMD_52:      /* IO R/W Direct (single byte) - Response R5 */
+               cmd52data = GFIELD(cmd_arg, CMD52_DATA);
+               cmd_arg = arg;
+               cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD52_FUNCTION));
+               cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD52_REG_ADDR));
+               /* Display trace for byte write */
+               if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {
+                       sd_trace(("%s: CMD52: Wr F:%d @0x%04x=%02x\n",
+                                 __FUNCTION__,
+                                 GFIELD(cmd_arg, CMD52_FUNCTION),
+                                 GFIELD(cmd_arg, CMD52_REG_ADDR),
+                                 cmd52data));
+               }
+
+               spi_datalen = 32;
+               spi_max_response_pad = 28;
+
+               break;
+       case SDIOH_CMD_53:      /* IO R/W Extended (multiple bytes/blocks) */
+               cmd_arg = arg;
+               cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD53_FUNCTION));
+               cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD53_REG_ADDR));
+               cmd_reg = SFIELD(cmd_reg, SPI_BLKMODE, 0);
+               cmd_reg = SFIELD(cmd_reg, SPI_OPCODE, GFIELD(cmd_arg, CMD53_OP_CODE));
+               cmd_reg = SFIELD(cmd_reg, SPI_STUFF0, (sd->data_xfer_count>>8));
+               cmd52data = (uint8)sd->data_xfer_count;
+
+               /* Set upper bit in byte count if necessary, but don't set it for 512 bytes. */
+               if ((sd->data_xfer_count > 255) && (sd->data_xfer_count < 512)) {
+                       cmd_reg |= 1;
+               }
+
+               if (GFIELD(cmd_reg, SPI_RW) == 1) { /* Write */
+                       spi_max_response_pad = 32;
+                       spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
+               } else { /* Read */
+
+                       spi_max_response_pad = 32;
+                       spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
+               }
+               sd_trace(("%s: CMD53: %s F:%d @0x%04x len=0x%02x\n",
+                         __FUNCTION__,
+                         (GFIELD(cmd_reg, SPI_RW) == 1 ? "Wr" : "Rd"),
+                         GFIELD(cmd_arg, CMD53_FUNCTION),
+                         GFIELD(cmd_arg, CMD53_REG_ADDR),
+                         cmd52data));
+               break;
+
+       default:
+               sd_err(("%s: Unknown command %d\n", __FUNCTION__, cmd));
+               return ERROR;
+       }
+
+       /* Set up and issue the SDIO command */
+       memset(spi_databuf, SDSPI_IDLE_PAD, spi_datalen);
+       spi_databuf[spi_pre_cmd_pad + 0] = (cmd_reg & 0xFF000000) >> 24;
+       spi_databuf[spi_pre_cmd_pad + 1] = (cmd_reg & 0x00FF0000) >> 16;
+       spi_databuf[spi_pre_cmd_pad + 2] = (cmd_reg & 0x0000FF00) >> 8;
+       spi_databuf[spi_pre_cmd_pad + 3] = (cmd_reg & 0x000000FF);
+       spi_databuf[spi_pre_cmd_pad + 4] = cmd52data;
+
+       /* Generate CRC7 for command, if CRC is enabled, otherwise, a
+        * default CRC7 of 0x95, which is correct for CMD0, is used.
+        */
+       if (sd_crc) {
+               cmd_crc = sdspi_crc7(&spi_databuf[spi_pre_cmd_pad], 5);
+       }
+       spi_databuf[spi_pre_cmd_pad + 5] = cmd_crc;
+#define SPI_STOP_TRAN          0xFD
+
+       /* for CMD53 Write, put the data into the output buffer  */
+       if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD53_RW_FLAG) == 1)) {
+               if (datalen != 0) {
+                       spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
+                       spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
+
+                       for (i = 0; i < sd->data_xfer_count; i++) {
+                               spi_databuf[i + 11 + spi_pre_cmd_pad] = ((uint8 *)data)[i];
+                       }
+                       if (sd_crc) {
+                               dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], i);
+                       } else {
+                               dat_crc = 0xAAAA;
+                       }
+                       spi_databuf[i + 11 + spi_pre_cmd_pad] = (dat_crc >> 8) & 0xFF;
+                       spi_databuf[i + 12 + spi_pre_cmd_pad] = dat_crc & 0xFF;
+               } else if (sd->data_xfer_count == 2) {
+                       spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
+                       spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
+                       spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF;
+                       spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
+                       if (sd_crc) {
+                               dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 2);
+                       } else {
+                               dat_crc = 0x22AA;
+                       }
+                       spi_databuf[spi_pre_cmd_pad + 13] = (dat_crc >> 8) & 0xFF;
+                       spi_databuf[spi_pre_cmd_pad + 14] = (dat_crc & 0xFF);
+               } else if (sd->data_xfer_count == 4) {
+                       spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
+                       spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
+                       spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF;
+                       spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
+                       spi_databuf[spi_pre_cmd_pad + 13] = (sd->cmd53_wr_data & 0x00FF0000) >> 16;
+                       spi_databuf[spi_pre_cmd_pad + 14] = (sd->cmd53_wr_data & 0xFF000000) >> 24;
+                       if (sd_crc) {
+                               dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 4);
+                       } else {
+                               dat_crc = 0x44AA;
+                       }
+                       spi_databuf[spi_pre_cmd_pad + 15] = (dat_crc >> 8) & 0xFF;
+                       spi_databuf[spi_pre_cmd_pad + 16] = (dat_crc & 0xFF);
+               } else {
+                       printf("CMD53 Write: size %d unsupported\n", sd->data_xfer_count);
+               }
+       }
+
+       spi_sendrecv(sd, spi_databuf, spi_rspbuf, spi_datalen);
+
+       for (i = spi_pre_cmd_pad + SDSPI_COMMAND_LEN; i < spi_max_response_pad; i++) {
+               if ((spi_rspbuf[i] & SDSPI_START_BIT_MASK) == 0) {
+                       break;
+               }
+       }
+
+       if (i == spi_max_response_pad) {
+               sd_err(("%s: Did not get a response for CMD%d\n", __FUNCTION__, cmd));
+               return ERROR;
+       }
+
+       /* Extract the response. */
+       sd->card_response = spi_rspbuf[i];
+
+       /* for CMD53 Read, find the start of the response data... */
+       if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
+               for (; i < spi_max_response_pad; i++) {
+                       if (spi_rspbuf[i] == SDSPI_START_BLOCK) {
+                               break;
+                       }
+               }
+
+               if (i == spi_max_response_pad) {
+                       printf("Did not get a start of data phase for CMD%d\n", cmd);
+                       max_errors++;
+                       sdspi_abort(sd, GFIELD(cmd_arg, CMD53_FUNCTION));
+               }
+               sd->card_rsp_data = spi_rspbuf[i+1];
+               sd->card_rsp_data |= spi_rspbuf[i+2] << 8;
+               sd->card_rsp_data |= spi_rspbuf[i+3] << 16;
+               sd->card_rsp_data |= spi_rspbuf[i+4] << 24;
+
+               if (datalen != 0) {
+                       i++;
+                       for (j = 0; j < sd->data_xfer_count; j++) {
+                               ((uint8 *)data)[j] = spi_rspbuf[i+j];
+                       }
+                       if (sd_crc) {
+                               uint16 recv_crc;
+
+                               recv_crc = spi_rspbuf[i+j] << 8 | spi_rspbuf[i+j+1];
+                               dat_crc = sdspi_crc16((uint8 *)data, datalen);
+                               if (dat_crc != recv_crc) {
+                                       sd_err(("%s: Incorrect data CRC: expected 0x%04x, "
+                                               "received 0x%04x\n",
+                                               __FUNCTION__, dat_crc, recv_crc));
+                               }
+                       }
+               }
+               return SUCCESS;
+       }
+
+       sd->card_rsp_data = spi_rspbuf[i+4];
+       sd->card_rsp_data |= spi_rspbuf[i+3] << 8;
+       sd->card_rsp_data |= spi_rspbuf[i+2] << 16;
+       sd->card_rsp_data |= spi_rspbuf[i+1] << 24;
+
+       /* Display trace for byte read */
+       if ((cmd == SDIOH_CMD_52) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
+               sd_trace(("%s: CMD52: Rd F:%d @0x%04x=%02x\n",
+                         __FUNCTION__,
+                         GFIELD(cmd_arg, CMD53_FUNCTION),
+                         GFIELD(cmd_arg, CMD53_REG_ADDR),
+                         sd->card_rsp_data >> 24));
+       }
+
+       return SUCCESS;
+}
+
+/*
+ * On entry: if single-block or non-block, buffer size <= block size.
+ * If multi-block, buffer size is unlimited.
+ * Question is how to handle the left-overs in either single- or multi-block.
+ * I think the caller should break the buffer up so this routine will always
+ * use block size == buffer size to handle the end piece of the buffer
+ */
+
+static int
+sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data)
+{
+       int status;
+       uint32 cmd_arg;
+       uint32 rsp5;
+       int num_blocks, blocksize;
+       bool local_blockmode, local_dma;
+       bool read = rw == SDIOH_READ ? 1 : 0;
+
+       ASSERT(nbytes);
+
+       cmd_arg = 0;
+       sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
+                __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
+                addr, nbytes, sd->r_cnt, sd->t_cnt));
+
+       if (read) sd->r_cnt++; else sd->t_cnt++;
+
+       local_blockmode = sd->sd_blockmode;
+       local_dma = sd->sd_use_dma;
+
+       /* Don't bother with block mode on small xfers */
+       if (nbytes < sd->client_block_size[func]) {
+               sd_info(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n",
+                        nbytes, sd->client_block_size[func]));
+               local_blockmode = FALSE;
+               local_dma = FALSE;
+       }
+
+       if (local_blockmode) {
+               blocksize = MIN(sd->client_block_size[func], nbytes);
+               num_blocks = nbytes/blocksize;
+               cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks);
+               cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1);
+       } else {
+               num_blocks =  1;
+               blocksize = nbytes;
+               cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes);
+               cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
+       }
+
+       if (fifo)
+               cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0);
+       else
+               cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
+
+       cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
+       cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr);
+       if (read)
+               cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
+       else
+               cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
+
+       sd->data_xfer_count = nbytes;
+       if ((func == 2) && (fifo == 1)) {
+               sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
+                        __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
+                        addr, nbytes, sd->r_cnt, sd->t_cnt));
+       }
+
+       /* sdspi_cmd_issue() returns with the command complete bit
+        * in the ISR already cleared
+        */
+       if ((status = sdspi_cmd_issue(sd, local_dma,
+                                     SDIOH_CMD_53, cmd_arg,
+                                     data, nbytes)) != SUCCESS) {
+               sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write")));
+               return status;
+       }
+
+       sdspi_cmd_getrsp(sd, &rsp5, 1);
+
+       if (rsp5 != 0x00) {
+               sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
+                       __FUNCTION__,  rsp5));
+               return ERROR;
+       }
+
+       return SUCCESS;
+}
+
+static int
+set_client_block_size(sdioh_info_t *sd, int func, int block_size)
+{
+       int base;
+       int err = 0;
+
+       sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func));
+       sd->client_block_size[func] = block_size;
+
+       /* Set the block size in the SDIO Card register */
+       base = func * SDIOD_FBR_SIZE;
+       err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff);
+       if (!err) {
+               err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_1, 1,
+                                         (block_size >> 8) & 0xff);
+       }
+
+       /*
+        * Do not set the block size in the SDIO Host register; that
+        * is func dependent and will get done on an individual
+        * transaction basis.
+        */
+
+       return (err ? BCME_SDIO_ERROR : 0);
+}
+
+/* Reset and re-initialize the device */
+int
+sdioh_sdio_reset(sdioh_info_t *si)
+{
+       si->card_init_done = FALSE;
+       return sdspi_client_init(si);
+}
+
+#define CRC7_POLYNOM   0x09
+#define CRC7_CRCHIGHBIT        0x40
+
+static uint8 sdspi_crc7(unsigned char* p, uint32 len)
+{
+       uint8 c, j, bit, crc = 0;
+       uint32 i;
+
+       for (i = 0; i < len; i++) {
+               c = *p++;
+               for (j = 0x80; j; j >>= 1) {
+                       bit = crc & CRC7_CRCHIGHBIT;
+                       crc <<= 1;
+                       if (c & j) bit ^= CRC7_CRCHIGHBIT;
+                       if (bit) crc ^= CRC7_POLYNOM;
+               }
+       }
+
+       /* Convert the CRC7 to an 8-bit SD CRC */
+       crc = (crc << 1) | 1;
+
+       return (crc);
+}
+
+#define CRC16_POLYNOM  0x1021
+#define CRC16_CRCHIGHBIT       0x8000
+
+static uint16 sdspi_crc16(unsigned char* p, uint32 len)
+{
+       uint32 i;
+       uint16 j, c, bit;
+       uint16 crc = 0;
+
+       for (i = 0; i < len; i++) {
+               c = *p++;
+               for (j = 0x80; j; j >>= 1) {
+                       bit = crc & CRC16_CRCHIGHBIT;
+                       crc <<= 1;
+                       if (c & j) bit ^= CRC16_CRCHIGHBIT;
+                       if (bit) crc ^= CRC16_POLYNOM;
+               }
+       }
+
+       return (crc);
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c
new file mode 100644 (file)
index 0000000..1046a17
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Broadcom SPI Host Controller Driver - Linux Per-port
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdspi_linux.c,v 1.7.2.1.4.3 2008/06/30 21:09:36 Exp $
+ */
+
+#include <typedefs.h>
+#include <pcicfg.h>
+#include <bcmutils.h>
+
+#include <sdio.h>              /* SDIO Specs */
+#include <bcmsdbus.h>          /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>           /* to get msglevel bit values */
+
+#include <linux/sched.h>       /* request_irq(), free_irq() */
+
+#include <bcmsdspi.h>
+#include <bcmspi.h>
+
+extern uint sd_crc;
+module_param(sd_crc, uint, 0);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define KERNEL26
+#endif
+
+struct sdos_info {
+       sdioh_info_t *sd;
+       spinlock_t lock;
+       wait_queue_head_t intr_wait_queue;
+};
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define BLOCKABLE()    (!in_atomic())
+#else
+#define BLOCKABLE()    (!in_interrupt())
+#endif
+
+/* Interrupt handler */
+static irqreturn_t
+sdspi_isr(int irq, void *dev_id
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+, struct pt_regs *ptregs
+#endif
+)
+{
+       sdioh_info_t *sd;
+       struct sdos_info *sdos;
+       bool ours;
+
+       sd = (sdioh_info_t *)dev_id;
+       sd->local_intrcount++;
+
+       if (!sd->card_init_done) {
+               sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq));
+               return IRQ_RETVAL(FALSE);
+       } else {
+               ours = spi_check_client_intr(sd, NULL);
+
+               /* For local interrupts, wake the waiting process */
+               if (ours && sd->got_hcint) {
+                       sdos = (struct sdos_info *)sd->sdos_info;
+                       wake_up_interruptible(&sdos->intr_wait_queue);
+               }
+
+               return IRQ_RETVAL(ours);
+       }
+}
+
+/* Register with Linux for interrupts */
+int
+spi_register_irq(sdioh_info_t *sd, uint irq)
+{
+       sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq));
+       if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) {
+               sd_err(("%s: request_irq() failed\n", __FUNCTION__));
+               return ERROR;
+       }
+       return SUCCESS;
+}
+
+/* Free Linux irq */
+void
+spi_free_irq(uint irq, sdioh_info_t *sd)
+{
+       free_irq(irq, sd);
+}
+
+/* Map Host controller registers */
+
+uint32 *
+spi_reg_map(osl_t *osh, uintptr addr, int size)
+{
+       return (uint32 *)REG_MAP(addr, size);
+}
+
+void
+spi_reg_unmap(osl_t *osh, uintptr addr, int size)
+{
+       REG_UNMAP((void*)(uintptr)addr);
+}
+
+int
+spi_osinit(sdioh_info_t *sd)
+{
+       struct sdos_info *sdos;
+
+       sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
+       sd->sdos_info = (void*)sdos;
+       if (sdos == NULL)
+               return BCME_NOMEM;
+
+       sdos->sd = sd;
+       spin_lock_init(&sdos->lock);
+       init_waitqueue_head(&sdos->intr_wait_queue);
+       return BCME_OK;
+}
+
+void
+spi_osfree(sdioh_info_t *sd)
+{
+       struct sdos_info *sdos;
+       ASSERT(sd && sd->sdos_info);
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       MFREE(sd->osh, sdos, sizeof(struct sdos_info));
+}
+
+/* Interrupt enable/disable */
+SDIOH_API_RC
+sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
+{
+       ulong flags;
+       struct sdos_info *sdos;
+
+       sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       ASSERT(sdos);
+
+       if (!(sd->host_init_done && sd->card_init_done)) {
+               sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__));
+               return SDIOH_API_RC_FAIL;
+       }
+
+       if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
+               sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
+               return SDIOH_API_RC_FAIL;
+       }
+
+       /* Ensure atomicity for enable/disable calls */
+       spin_lock_irqsave(&sdos->lock, flags);
+
+       sd->client_intr_enabled = enable;
+       if (enable && !sd->lockcount)
+               spi_devintr_on(sd);
+       else
+               spi_devintr_off(sd);
+
+       spin_unlock_irqrestore(&sdos->lock, flags);
+
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Protect against reentrancy (disable device interrupts while executing) */
+void
+spi_lock(sdioh_info_t *sd)
+{
+       ulong flags;
+       struct sdos_info *sdos;
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       ASSERT(sdos);
+
+       sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount));
+
+       spin_lock_irqsave(&sdos->lock, flags);
+       if (sd->lockcount) {
+               sd_err(("%s: Already locked!\n", __FUNCTION__));
+               ASSERT(sd->lockcount == 0);
+       }
+       spi_devintr_off(sd);
+       sd->lockcount++;
+       spin_unlock_irqrestore(&sdos->lock, flags);
+}
+
+/* Enable client interrupt */
+void
+spi_unlock(sdioh_info_t *sd)
+{
+       ulong flags;
+       struct sdos_info *sdos;
+
+       sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled));
+       ASSERT(sd->lockcount > 0);
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+       ASSERT(sdos);
+
+       spin_lock_irqsave(&sdos->lock, flags);
+       if (--sd->lockcount == 0 && sd->client_intr_enabled) {
+               spi_devintr_on(sd);
+       }
+       spin_unlock_irqrestore(&sdos->lock, flags);
+}
+
+void spi_waitbits(sdioh_info_t *sd, bool yield)
+{
+       struct sdos_info *sdos;
+
+       sdos = (struct sdos_info *)sd->sdos_info;
+
+#ifndef BCMSDYIELD
+       ASSERT(!yield);
+#endif
+       sd_trace(("%s: yield %d canblock %d\n",
+                 __FUNCTION__, yield, BLOCKABLE()));
+
+       /* Clear the "interrupt happened" flag and last intrstatus */
+       sd->got_hcint = FALSE;
+
+#ifdef BCMSDYIELD
+       if (yield && BLOCKABLE()) {
+               /* Wait for the indication, the interrupt will be masked when the ISR fires. */
+               wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint));
+       } else
+#endif /* BCMSDYIELD */
+       {
+               spi_spinbits(sd);
+       }
+
+}
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd.c b/bcm4329/src/bcmsdio/sys/bcmsdstd.c
new file mode 100644 (file)
index 0000000..2665716
--- /dev/null
@@ -0,0 +1,2795 @@
+/*
+ *  'Standard' SDIO HOST CONTROLLER driver
+ *
+ * Copyright (C) 1999-2009, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: bcmsdstd.c,v 1.64.4.1.4.4.2.10 2009/05/22 00:31:44 Exp $
+ */
+
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <siutils.h>
+#include <sdio.h>      /* SDIO Device and Protocol Specs */
+#include <sdioh.h>     /* SDIO Host Controller Specification */
+#include <bcmsdbus.h>  /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h>   /* ioctl/iovars */
+
+#include <pcicfg.h>
+
+
+#define SD_PAGE 4096
+
+#include <bcmsdstd.h>
+
+/* Globals */
+uint sd_msglevel = SDH_ERROR_VAL;
+uint sd_hiok = TRUE;                   /* Use hi-speed mode if available? */
+uint sd_sdmode = SDIOH_MODE_SD4;       /* Use SD4 mode by default */
+uint sd_f2_blocksize = 64;             /* Default blocksize */
+
+#ifdef BCMSDYIELD
+bool sd_yieldcpu = TRUE;               /* Allow CPU yielding for buffer requests */
+uint sd_minyield = 0;                  /* Minimum xfer size to allow CPU yield */
+bool sd_forcerb = FALSE;               /* Force sync readback in intrs_on/off */
+#endif
+
+uint sd_divisor = 2;                   /* Default 48MHz/2 = 24MHz */
+
+uint sd_power = 1;             /* Default to SD Slot powered ON */
+uint sd_clock = 1;             /* Default to SD Clock turned ON */
+
+uint sd_toctl = 7;
+
+static bool trap_errs = FALSE;
+
+/* Prototypes */
+static bool sdstd_start_clock(sdioh_info_t *sd, uint16 divisor);
+static bool sdstd_start_power(sdioh_info_t *sd);
+static bool sdstd_bus_width(sdioh_info_t *sd, int width);
+static int sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
+static int sdstd_card_enablefuncs(sdioh_info_t *sd);
+static void sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
+static int sdstd_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg);
+static int sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
+                              int regsize, uint32 *data);
+static int sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
+                               int regsize, uint32 data);
+static int sdstd_driver_init(sdioh_info_t *sd);
+static bool sdstd_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
+static int sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
+                          uint32 addr, int nbytes, uint32 *data);
+static int sdstd_abort(sdioh_info_t *sd, uint func);
+static int sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg);
+static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
+static void sd_map_dma(sdioh_info_t * sd);
+static void sd_unmap_dma(sdioh_info_t * sd);
+
+/*
+ * Private register access routines.
+ */
+
+/* 16 bit PCI regs */
+
+extern uint16 sdstd_rreg16(sdioh_info_t *sd, uint reg);
+uint16
+sdstd_rreg16(sdioh_info_t *sd, uint reg)
+{
+
+       volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
+       sd_ctrl(("16: R Reg 0x%02x, Data 0x%x\n", reg, data));
+       return data;
+}
+
+extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data);
+void
+sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data)
+{
+       *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16) data;
+       sd_ctrl(("16: W Reg 0x%02x, Data 0x%x\n", reg, data));
+}
+
+static void
+sdstd_or_reg16(sdioh_info_t *sd, uint reg, uint16 val)
+{
+       volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
+       sd_ctrl(("16: OR Reg 0x%02x, Val 0x%x\n", reg, val));
+       data |= val;
+       *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data;
+
+}
+static void
+sdstd_mod_reg16(sdioh_info_t *sd, uint reg, int16 mask, uint16 val)
+{
+
+       volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
+       sd_ctrl(("16: MOD Reg 0x%02x, Mask 0x%x, Val 0x%x\n", reg, mask, val));
+       data &= ~mask;
+       data |= (val & mask);
+       *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data;
+}
+
+
+/* 32 bit PCI regs */
+static uint32
+sdstd_rreg(sdioh_info_t *sd, uint reg)
+{
+       volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg);
+       sd_ctrl(("32: R Reg 0x%02x, Data 0x%x\n", reg, data));
+       return data;
+}
+static inline void
+sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data)
+{
+       *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data;
+       sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data));
+
+}
+
+/* 8 bit PCI regs */
+static inline void
+sdstd_wreg8(sdioh_info_t *sd, uint reg, uint8 data)
+{
+       *(volatile uint8 *)(sd->mem_space + reg) = (volatile uint8)data;
+       sd_ctrl(("08: W Reg 0x%02x, Data 0x%x\n", reg, data));
+}
+static uint8
+sdstd_rreg8(sdioh_info_t *sd, uint reg)
+{
+       volatile uint8 data = *(volatile uint8 *)(sd->mem_space + reg);
+       sd_ctrl(("08: R Reg 0x%02x, Data 0x%x\n", reg, data));
+       return data;
+}
+
+/*
+ * Private work routines
+ */
+
+sdioh_info_t *glob_sd;
+
+/*
+ *  Public entry points & extern's
+ */
+extern sdioh_info_t *
+sdioh_attach(osl_t *osh, void *bar0, uint irq)
+{
+       sdioh_info_t *sd;
+
+       sd_trace(("%s\n", __FUNCTION__));
+       if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
+               sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
+               return NULL;
+       }
+       bzero((char *)sd, sizeof(sdioh_info_t));
+       glob_sd = sd;
+       sd->osh = osh;
+       if (sdstd_osinit(sd) != 0) {
+               sd_err(("%s:sdstd_osinit() failed\n", __FUNCTION__));
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return NULL;
+       }
+       sd->mem_space = (volatile char *)sdstd_reg_map(osh, (uintptr)bar0, SDIOH_REG_WINSZ);
+       sd_init_dma(sd);
+       sd->irq = irq;
+       if (sd->mem_space == NULL) {
+               sd_err(("%s:ioremap() failed\n", __FUNCTION__));
+               sdstd_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return NULL;
+       }
+       sd_info(("%s:sd->mem_space = %p\n", __FUNCTION__, sd->mem_space));
+       sd->intr_handler = NULL;
+       sd->intr_handler_arg = NULL;
+       sd->intr_handler_valid = FALSE;
+
+       /* Set defaults */
+       sd->sd_blockmode = TRUE;
+       sd->use_client_ints = TRUE;
+       sd->sd_use_dma = TRUE;
+
+       if (!sd->sd_blockmode)
+               sd->sd_use_dma = 0;
+
+       if (sd->sd_use_dma) {
+               OSL_DMADDRWIDTH(osh, 32);
+               sd_map_dma(sd);
+       }
+
+       if (sdstd_driver_init(sd) != SUCCESS) {
+               /* If host CPU was reset without resetting SD bus or
+                  SD device, the device will still have its RCA but
+                  driver no longer knows what it is (since driver has been restarted).
+                  go through once to clear the RCA and a gain reassign it.
+                */
+               sd_info(("driver_init failed - Reset RCA and try again\n"));
+               if (sdstd_driver_init(sd) != SUCCESS) {
+                       sd_err(("%s:driver_init() failed()\n", __FUNCTION__));
+                       if (sd->mem_space) {
+                               sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
+                               sd->mem_space = NULL;
+                       }
+                       sdstd_osfree(sd);
+                       MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+                       return (NULL);
+               }
+       }
+
+       if (sdstd_register_irq(sd, irq) != SUCCESS) {
+               sd_err(("%s: sdstd_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
+               sdstd_free_irq(sd->irq, sd);
+               if (sd->mem_space) {
+                       sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
+                       sd->mem_space = NULL;
+               }
+
+               sdstd_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+               return (NULL);
+       }
+
+       sd_trace(("%s: Done\n", __FUNCTION__));
+       return sd;
+}
+
+extern SDIOH_API_RC
+sdioh_detach(osl_t *osh, sdioh_info_t *sd)
+{
+       sd_trace(("%s\n", __FUNCTION__));
+       if (sd) {
+               sd_unmap_dma(sd);
+               sdstd_wreg16(sd, SD_IntrSignalEnable, 0);
+               sd_trace(("%s: freeing irq %d\n", __FUNCTION__, sd->irq));
+               sdstd_free_irq(sd->irq, sd);
+               if (sd->card_init_done)
+                       sdstd_reset(sd, 1, 1);
+               if (sd->mem_space) {
+                       sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
+                       sd->mem_space = NULL;
+               }
+
+               sdstd_osfree(sd);
+               MFREE(sd->osh, sd, sizeof(sdioh_info_t));
+       }
+       return SDIOH_API_RC_SUCCESS;
+}
+
+/* Configure callback to client when we recieve client interrupt */
+extern SDIOH_API_RC
+sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+       sd->intr_handler = fn;
+       sd->intr_handler_arg = argh;
+       sd->intr_handler_valid = TRUE;
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_deregister(sdioh_info_t *sd)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+       sd->intr_handler_valid = FALSE;
+       sd->intr_handler = NULL;
+       sd->intr_handler_arg = NULL;
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
+{
+       sd_trace(("%s: Entering\n", __FUNCTION__));
+       *onoff = sd->client_intr_enabled;
+       return SDIOH_API_RC_SUCCESS;
+}
+
+#if defined(DHD_DEBUG)
+extern bool
+sdioh_interrupt_pending(sdioh_info_t *sd)
+{
+       uint16 intrstatus;
+       intrstatus = sdstd_rreg16(sd, SD_IntrStatus);
+       return !!(intrstatus & CLIENT_INTR);
+}
+#endif
+
+uint
+sdioh_query_iofnum(sdioh_info_t *sd)
+{
+       return sd->num_funcs;
+}
+
+/* IOVar table */
+enum {
+       IOV_MSGLEVEL = 1,
+       IOV_BLOCKMODE,
+       IOV_BLOCKSIZE,
+       IOV_DMA,
+       IOV_USEINTS,
+       IOV_NUMINTS,
+       IOV_NUMLOCALINTS,
+       IOV_HOSTREG,
+       IOV_DEVREG,
+       IOV_DIVISOR,
+       IOV_SDMODE,
+       IOV_HISPEED,
+       IOV_HCIREGS,
+       IOV_POWER,
+       IOV_YIELDCPU,
+       IOV_MINYIELD,
+       IOV_FORCERB,
+       IOV_CLOCK
+};
+
+const bcm_iovar_t sdioh_iovars[] = {
+       {"sd_msglevel", IOV_MSGLEVEL,   0,      IOVT_UINT32,    0 },
+       {"sd_blockmode", IOV_BLOCKMODE, 0,      IOVT_BOOL,      0 },
+       {"sd_blocksize", IOV_BLOCKSIZE, 0,      IOVT_UINT32,    0 }, /* ((fn << 16) | size) */
+       {"sd_dma",      IOV_DMA,        0,      IOVT_BOOL,      0 },
+#ifdef BCMSDYIELD
+       {"sd_yieldcpu", IOV_YIELDCPU,   0,      IOVT_BOOL,      0 },
+       {"sd_minyield", IOV_MINYIELD,   0,      IOVT_UINT32,    0 },
+       {"sd_forcerb",  IOV_FORCERB,    0,      IOVT_BOOL,      0 },
+#endif
+       {"sd_ints",     IOV_USEINTS,    0,      IOVT_BOOL,      0 },
+       {"sd_numints",  IOV_NUMINTS,    0,      IOVT_UINT32,    0 },
+       {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32,   0 },
+       {"sd_hostreg",  IOV_HOSTREG,    0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_devreg",   IOV_DEVREG,     0,      IOVT_BUFFER,    sizeof(sdreg_t) },
+       {"sd_divisor",  IOV_DIVISOR,    0,      IOVT_UINT32,    0 },
+       {"sd_power",    IOV_POWER,      0,      IOVT_UINT32,    0 },
+       {"sd_clock",    IOV_CLOCK,      0,      IOVT_UINT32,    0 },
+       {"sd_mode",     IOV_SDMODE,     0,      IOVT_UINT32,    100},
+       {"sd_highspeed",        IOV_HISPEED,    0,      IOVT_UINT32,    0},
+       {NULL, 0, 0, 0, 0 }
+};
+
+int
+sdioh_iovar_op(sdioh_info_t *si, const char *name,
+               void *params, int plen, void *arg, int len, bool set)
+{
+       const bcm_iovar_t *vi = NULL;
+       int bcmerror = 0;
+       int val_size;
+       int32 int_val = 0;
+       bool bool_val;
+       uint32 actionid;
+
+       ASSERT(name);
+       ASSERT(len >= 0);
+
+       /* Get must have return space; Set does not take qualifiers */
+       ASSERT(set || (arg && len));
+       ASSERT(!set || (!params && !plen));
+
+       sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
+
+       if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
+               bcmerror = BCME_UNSUPPORTED;
+               goto exit;
+       }
+
+       if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
+               goto exit;
+
+       /* Set up params so get and set can share the convenience variables */
+       if (params == NULL) {
+               params = arg;
+               plen = len;
+       }
+
+       if (vi->type == IOVT_VOID)
+               val_size = 0;
+       else if (vi->type == IOVT_BUFFER)
+               val_size = len;
+       else
+               val_size = sizeof(int);
+
+       if (plen >= (int)sizeof(int_val))
+               bcopy(params, &int_val, sizeof(int_val));
+
+       bool_val = (int_val != 0) ? TRUE : FALSE;
+
+       actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
+       switch (actionid) {
+       case IOV_GVAL(IOV_MSGLEVEL):
+               int_val = (int32)sd_msglevel;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_MSGLEVEL):
+               sd_msglevel = int_val;
+               break;
+
+       case IOV_GVAL(IOV_BLOCKMODE):
+               int_val = (int32)si->sd_blockmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKMODE):
+               si->sd_blockmode = (bool)int_val;
+               /* Haven't figured out how to make non-block mode with DMA */
+               if (!si->sd_blockmode)
+                       si->sd_use_dma = 0;
+               break;
+
+#ifdef BCMSDYIELD
+       case IOV_GVAL(IOV_YIELDCPU):
+               int_val = sd_yieldcpu;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_YIELDCPU):
+               sd_yieldcpu = (bool)int_val;
+               break;
+
+       case IOV_GVAL(IOV_MINYIELD):
+               int_val = sd_minyield;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_MINYIELD):
+               sd_minyield = (bool)int_val;
+               break;
+
+       case IOV_GVAL(IOV_FORCERB):
+               int_val = sd_forcerb;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_FORCERB):
+               sd_forcerb = (bool)int_val;
+               break;
+#endif /* BCMSDYIELD */
+
+       case IOV_GVAL(IOV_BLOCKSIZE):
+               if ((uint32)int_val > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               int_val = (int32)si->client_block_size[int_val];
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_BLOCKSIZE):
+       {
+               uint func = ((uint32)int_val >> 16);
+               uint blksize = (uint16)int_val;
+               uint maxsize;
+
+               if (func > si->num_funcs) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               switch (func) {
+               case 0: maxsize = 32; break;
+               case 1: maxsize = BLOCK_SIZE_4318; break;
+               case 2: maxsize = BLOCK_SIZE_4328; break;
+               default: maxsize = 0;
+               }
+               if (blksize > maxsize) {
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+               if (!blksize) {
+                       blksize = maxsize;
+               }
+
+               /* Now set it */
+               sdstd_lock(si);
+               bcmerror = set_client_block_size(si, func, blksize);
+               sdstd_unlock(si);
+               break;
+       }
+
+       case IOV_GVAL(IOV_DMA):
+               int_val = (int32)si->sd_use_dma;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DMA):
+               si->sd_use_dma = (bool)int_val;
+               break;
+
+       case IOV_GVAL(IOV_USEINTS):
+               int_val = (int32)si->use_client_ints;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_USEINTS):
+               si->use_client_ints = (bool)int_val;
+               if (si->use_client_ints)
+                       si->intmask |= CLIENT_INTR;
+               else
+                       si->intmask &= ~CLIENT_INTR;
+               break;
+
+       case IOV_GVAL(IOV_DIVISOR):
+               int_val = (uint32)sd_divisor;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_DIVISOR):
+               sd_divisor = int_val;
+               if (!sdstd_start_clock(si, (uint16)sd_divisor)) {
+                       sd_err(("set clock failed!\n"));
+                       bcmerror = BCME_ERROR;
+               }
+               break;
+
+       case IOV_GVAL(IOV_POWER):
+               int_val = (uint32)sd_power;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_POWER):
+               sd_power = int_val;
+               if (sd_power == 1) {
+                       if (sdstd_driver_init(si) != SUCCESS) {
+                               sd_err(("set SD Slot power failed!\n"));
+                               bcmerror = BCME_ERROR;
+                       } else {
+                               sd_err(("SD Slot Powered ON.\n"));
+                       }
+               } else {
+                       uint8 pwr = 0;
+
+                       pwr = SFIELD(pwr, PWR_BUS_EN, 0);
+                       sdstd_wreg8(si, SD_PwrCntrl, pwr); /* Set Voltage level */
+                       sd_err(("SD Slot Powered OFF.\n"));
+               }
+               break;
+
+       case IOV_GVAL(IOV_CLOCK):
+               int_val = (uint32)sd_clock;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_CLOCK):
+               sd_clock = int_val;
+               if (sd_clock == 1) {
+                       sd_info(("SD Clock turned ON.\n"));
+                       if (!sdstd_start_clock(si, (uint16)sd_divisor)) {
+                               sd_err(("sdstd_start_clock failed\n"));
+                               bcmerror = BCME_ERROR;
+                       }
+               } else {
+                       /* turn off HC clock */
+                       sdstd_wreg16(si, SD_ClockCntrl,
+                                    sdstd_rreg16(si, SD_ClockCntrl) & ~((uint16)0x4));
+
+                       sd_info(("SD Clock turned OFF.\n"));
+               }
+               break;
+
+       case IOV_GVAL(IOV_SDMODE):
+               int_val = (uint32)sd_sdmode;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_SDMODE):
+               sd_sdmode = int_val;
+
+               if (!sdstd_bus_width(si, sd_sdmode)) {
+                       sd_err(("sdstd_bus_width failed\n"));
+                       bcmerror = BCME_ERROR;
+               }
+               break;
+
+       case IOV_GVAL(IOV_HISPEED):
+               int_val = (uint32)sd_hiok;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_SVAL(IOV_HISPEED):
+               sd_hiok = int_val;
+               bcmerror = sdstd_set_highspeed_mode(si, (bool)sd_hiok);
+               break;
+
+       case IOV_GVAL(IOV_NUMINTS):
+               int_val = (int32)si->intrcount;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_NUMLOCALINTS):
+               int_val = (int32)si->local_intrcount;
+               bcopy(&int_val, arg, val_size);
+               break;
+
+       case IOV_GVAL(IOV_HOSTREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+
+               if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+                       sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
+                         (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+                         sd_ptr->offset));
+               if (sd_ptr->offset & 1)
+                       int_val = sdstd_rreg8(si, sd_ptr->offset);
+               else if (sd_ptr->offset & 2)
+                       int_val = sdstd_rreg16(si, sd_ptr->offset);
+               else
+                       int_val = sdstd_rreg(si, sd_ptr->offset);
+
+               bcopy(&int_val, arg, sizeof(int_val));
+               break;
+       }
+
+       case IOV_SVAL(IOV_HOSTREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+
+               if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+                       sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+                       bcmerror = BCME_BADARG;
+                       break;
+               }
+
+               sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
+                         (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+                         sd_ptr->offset));
+               if (sd_ptr->offset & 1)
+                       sdstd_wreg8(si, sd_ptr->offset, (uint8)sd_ptr->value);
+               else if (sd_ptr->offset & 2)
+                       sdstd_wreg16(si, sd_ptr->offset, (uint16)sd_ptr->value);
+               else
+                       sdstd_wreg(si, sd_ptr->offset, (uint32)sd_ptr->value);
+
+               break;
+       }
+
+       case IOV_GVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data;
+
+               if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+
+               int_val = (int)data;
+               bcopy(&int_val, arg, sizeof(int_val));
+               break;
+       }
+
+       case IOV_SVAL(IOV_DEVREG):
+       {
+               sdreg_t *sd_ptr = (sdreg_t *)params;
+               uint8 data = (uint8)sd_ptr->value;
+
+               if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
+                       bcmerror = BCME_SDIO_ERROR;
+                       break;
+               }
+               break;
+       }
+
+
+       default:
+               bcmerror = BCME_UNSUPPORTED;
+               break;
+       }
+exit:
+
+       return bcmerror;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       SDIOH_API_RC status;
+       /* No lock needed since sdioh_request_byte does locking */
+       status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
+       return status;
+}
+
+extern SDIOH_API_RC
+sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
+{
+       /* No lock needed since sdioh_request_byte does locking */
+       SDIOH_API_RC status;
+       status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
+       return status;
+}
+
+extern SDIOH_API_RC
+sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
+{
+       uint32 count;
+       int offset;
+       uint32 foo;
+       uint8 *cis = cisd;
+
+       sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
+
+       if (!sd->func_cis_ptr[func]) {
+               bzero(cis, length);
+               return SDIOH_API_RC_FAIL;
+       }
+
+       sdstd_lock(sd);
+       *cis = 0;
+       for (count = 0; count < length; count++) {
+               offset =  sd->func_cis_ptr[func] + count;
+               if (sdstd_card_regread(sd, 0, offset, 1, &foo)) {
+                       sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
+                       sdstd_unlock(sd);
+                       return SDIOH_API_RC_FAIL;
+               }
+               *cis = (uint8)(foo & 0xff);
+               cis++;
+       }
+       sdstd_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
+{
+       int status;
+       uint32 cmd_arg;
+       uint32 rsp5;
+
+       sdstd_lock(sd);
+       cmd_arg = 0;
+       cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
+       cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
+       cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte);
+
+       if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg)) != SUCCESS) {
+               sdstd_unlock(sd);
+               return status;
+       }
+
+       sdstd_cmd_getrsp(sd, &rsp5, 1);
+       if (sdstd_rreg16 (sd, SD_ErrorIntrStatus) != 0) {
+               sd_err(("%s: 1: ErrorintrStatus 0x%x\n",
+                       __FUNCTION__, sdstd_rreg16(sd, SD_ErrorIntrStatus)));
+       }
+       if (GFIELD(rsp5, RSP5_FLAGS) != 0x10)
+               sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
+                       __FUNCTION__, GFIELD(rsp5, RSP5_FLAGS), func));
+
+       if (GFIELD(rsp5, RSP5_STUFF))
+               sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
+                       __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
+
+       if (rw == SDIOH_READ)
+               *byte = GFIELD(rsp5, RSP5_DATA);
+
+       sdstd_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+extern SDIOH_API_RC
+sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
+                   uint32 *word, uint nbytes)
+{
+       int status;
+       bool swap = FALSE;
+
+       sdstd_lock(sd);
+
+       if (rw == SDIOH_READ) {
+               status = sdstd_card_regread(sd, func, addr, nbytes, word);
+               if (swap)
+                       *word = BCMSWAP32(*word);
+       } else {
+               if (swap)
+                       *word = BCMSWAP32(*word);
+               status = sdstd_card_regwrite(sd, func, addr, nbytes, *word);
+       }
+
+       sdstd_unlock(sd);
+       return (status == SUCCESS ?  SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+extern SDIOH_API_RC
+sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
+                     uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
+{
+       int len;
+       int buflen = (int)buflen_u;
+       bool fifo = (fix_inc == SDIOH_DATA_FIX);
+       uint8 *localbuf = NULL, *tmpbuf = NULL;
+       uint tmplen = 0;
+
+       sdstd_lock(sd);
+
+       ASSERT(reg_width == 4);
+       ASSERT(buflen_u < (1 << 30));
+       ASSERT(sd->client_block_size[func]);
+
+       sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
+                __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
+                buflen_u, sd->r_cnt, sd->t_cnt, pkt));
+
+       /* Break buffer down into blocksize chunks:
+        * Bytemode: 1 block at a time.
+        * Blockmode: Multiples of blocksizes at a time w/ max of SD_PAGE.
+        * Both: leftovers are handled last (will be sent via bytemode).
+        */
+       while (buflen > 0) {
+               if (sd->sd_blockmode) {
+                       /* Max xfer is Page size */
+                       len = MIN(SD_PAGE, buflen);
+
+                       /* Round down to a block boundry */
+                       if (buflen > sd->client_block_size[func])
+                               len = (len/sd->client_block_size[func]) *
+                                       sd->client_block_size[func];
+                       if ((func == SDIO_FUNC_1) && ((len % 4) == 3) && (rw == SDIOH_WRITE)) {
+                               tmplen = len;
+                               sd_err(("%s: Rounding up buffer to mod4 length.\n", __FUNCTION__));
+                               len++;
+                               tmpbuf = buffer;
+                               if ((localbuf = (uint8 *)MALLOC(sd->osh, len)) == NULL) {
+                                               sd_err(("out of memory, malloced %d bytes\n",
+                                                      MALLOCED(sd->osh)));
+                                               return SDIOH_API_RC_FAIL;
+                               }
+                               bcopy(buffer, localbuf, len);
+                               buffer = localbuf;
+                       }
+               } else {
+                       /* Byte mode: One block at a time */
+                       len = MIN(sd->client_block_size[func], buflen);
+               }
+
+               if (sdstd_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
+                       sdstd_unlock(sd);
+                       return SDIOH_API_RC_FAIL;
+               }
+
+               if (sd->sd_blockmode) {
+                       if ((func == SDIO_FUNC_1) && ((tmplen % 4) == 3) && (rw == SDIOH_WRITE)) {
+                               if (localbuf)
+                                       MFREE(sd->osh, localbuf, len);
+                               len--;
+                               buffer = tmpbuf;
+                               sd_err(("%s: Restoring back buffer ptr and len.\n", __FUNCTION__));
+                       }
+               }
+
+               buffer += len;
+               buflen -= len;
+               if (!fifo)
+                       addr += len;
+       }
+       sdstd_unlock(sd);
+       return SDIOH_API_RC_SUCCESS;
+}
+
+static
+int sdstd_abort(sdioh_info_t *sd, uint func)
+{
+       int err = 0;
+       int retries;
+
+       uint16 cmd_reg;
+       uint32 cmd_arg;
+       uint32 rsp5;
+       uint8 rflags;
+
+       uint16 int_reg = 0;
+       uint16 plain_intstatus;
+
+       /* Argument is write to F0 (CCCR) IOAbort with function number */
+       cmd_arg = 0;
+       cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, SDIO_FUNC_0);
+       cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, SDIOD_CCCR_IOABORT);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SD_IO_OP_WRITE);
+       cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
+       cmd_arg = SFIELD(cmd_arg, CMD52_DATA, func);
+
+       /* Command is CMD52 write */
+       cmd_reg = 0;
+       cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48_BUSY);
+       cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1);
+       cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1);
+       cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
+       cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_ABORT);
+       cmd_reg = SFIELD(cmd_reg, CMD_INDEX, SDIOH_CMD_52);
+
+       if (sd->sd_mode == SDIOH_MODE_SPI) {
+               cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
+               cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
+       }
+
+       /* Wait for CMD_INHIBIT to go away as per spec section 3.6.1.1 */
+       retries = RETRIES_SMALL;
+       while (GFIELD(sdstd_rreg(sd, SD_PresentState), PRES_CMD_INHIBIT)) {
+               if (retries == RETRIES_SMALL)
+                       sd_err(("%s: Waiting for Command Inhibit, state 0x%08x\n",
+                               __FUNCTION__, sdstd_rreg(sd, SD_PresentState)));
+               if (!--retries) {
+                       sd_err(("%s: Command Inhibit timeout, state 0x%08x\n",
+                               __FUNCTION__, sdstd_rreg(sd, SD_PresentState)));
+                       if (trap_errs)
+                               ASSERT(0);
+                       err = BCME_SDIO_ERROR;
+                       goto done;
+               }
+       }
+
+       /* Clear errors from any previous commands */
+       if ((plain_intstatus = sdstd_rreg16(sd, SD_ErrorIntrStatus)) != 0) {
+               sd_err(("abort: clearing errstat 0x%04x\n", plain_intstatus));
+               sdstd_wreg16(sd, SD_ErrorIntrStatus, plain_intstatus);
+       }
+       plain_intstatus = sdstd_rreg16(sd, SD_IntrStatus);
+       if (plain_intstatus & ~(SFIELD(0, INTSTAT_CARD_INT, 1))) {
+               sd_err(("abort: intstatus 0x%04x\n", plain_intstatus));
+               if (GFIELD(plain_intstatus, INTSTAT_CMD_COMPLETE)) {
+                       sd_err(("SDSTD_ABORT: CMD COMPLETE SET BEFORE COMMAND GIVEN!!!\n"));
+               }
+       }
+
+       /* Issue the command */
+       sdstd_wreg(sd, SD_Arg0, cmd_arg);
+       sdstd_wreg16(sd, SD_Command, cmd_reg);
+
+       /* In interrupt mode return, expect later CMD_COMPLETE interrupt */
+       if (!sd->polled_mode)
+               return err;
+
+       /* Otherwise, wait for the command to complete */
+       retries = RETRIES_LARGE;
+       do {
+               int_reg = sdstd_rreg16(sd, SD_IntrStatus);
+       } while (--retries &&
+                (GFIELD(int_reg, INTSTAT_ERROR_INT) == 0) &&
+                (GFIELD(int_reg, INTSTAT_CMD_COMPLETE) == 0));
+
+       /* If command completion fails, do a cmd reset and note the error */
+       if (!retries) {
+               sd_err(("%s: CMD_COMPLETE timeout: intr 0x%04x err 0x%04x state 0x%08x\n",
+                       __FUNCTION__, int_reg,
+                       sdstd_rreg16(sd, SD_ErrorIntrStatus),
+                       sdstd_rreg(sd, SD_PresentState)));
+
+               sdstd_wreg8(sd, SD_SoftwareReset, SFIELD(0, SW_RESET_CMD, 1));
+               retries = RETRIES_LARGE;
+               do {
+                       sd_trace(("%s: waiting for CMD line reset\n", __FUNCTION__));
+               } while ((GFIELD(sdstd_rreg8(sd, SD_SoftwareReset),
+                                SW_RESET_CMD)) && retries--);
+
+               if (!retries) {
+                       sd_err(("%s: Timeout waiting for CMD line reset\n", __FUNCTION__));
+               }
+
+               if (trap_errs)
+                       ASSERT(0);
+
+               err = BCME_SDIO_ERROR;
+       }
+
+       /* Clear Command Complete interrupt */
+       int_reg = SFIELD(0, INTSTAT_CMD_COMPLETE, 1);
+       sdstd_wreg16(sd, SD_IntrStatus, int_reg);
+
+       /* Check for Errors */
+       if ((plain_intstatus = sdstd_rreg16 (sd, SD_ErrorIntrStatus)) != 0) {
+               sd_err(("%s: ErrorintrStatus: 0x%x, "
+                       "(intrstatus = 0x%x, present state 0x%x) clearing\n",
+                       __FUNCTION__, plain_intstatus,
+                       sdstd_rreg16(sd, SD_IntrStatus),
+                       sdstd_rreg(sd, SD_PresentState)));
+
+               sdstd_wreg16(sd, SD_ErrorIntrStatus, plain_intstatus);
+
+               sdstd_wreg8(sd, SD_SoftwareReset, SFIELD(0, SW_RESET_DAT, 1));
+               retries = RETRIES_LARGE;
+               do {
+                       sd_trace(("%s: waiting for DAT line reset\n", __FUNCTION__));
+               } while ((GFIELD(sdstd_rreg8(sd, SD_SoftwareReset),
+                                SW_RESET_DAT)) && retries--);
+
+               if (!retries) {
+                       sd_err(("%s: Timeout waiting for DAT line reset\n", __FUNCTION__));
+               }
+
+               if (trap_errs)
+                       ASSERT(0);
+
+               /* ABORT is dataless, only cmd errs count */
+               if (plain_intstatus & ERRINT_CMD_ERRS)
+                       err = BCME_SDIO_ERROR;
+       }
+
+       /* If command failed don't bother looking at response */
+       if (err)
+               goto done;
+
+       /* Otherwise, check the response */
+       sdstd_cmd_getrsp(sd, &rsp5, 1);
+       rflags = GFIELD(rsp5, RSP5_FLAGS);
+
+       if (rflags & SD_RSP_R5_ERRBITS) {
+               sd_err(("%s: R5 flags include errbits: 0x%02x\n", __FUNCTION__, rflags));
+
+               /* The CRC error flag applies to the previous command */
+               if (rflags & (SD_RSP_R5_ERRBITS & ~SD_RSP_R5_COM_CRC_ERROR)) {
+                       err = BCME_SDIO_ERROR;
+                       goto done;
+               }
+       }
+
+       if (((rflags & (SD_RSP_R5_IO_CURRENTSTATE0 | SD_RSP_R5_IO_CURRENTSTATE1)) != 0x10) &&
+           ((rflags & (SD_RSP_R5_IO_CURRENTSTATE0 | SD_RSP_R5_IO_CURRENTSTATE1)) != 0x20)) {
+               sd_err(("%s: R5 flags has bad state: 0x%02x\n", __FUNCTION__, rflags));
+               err = BCME_SDIO_ERROR;
+               goto done;
+       }
+
+       if (GFIELD(rsp5, RSP5_STUFF)) {
+               sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
+                       __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
+               err = BCME_SDIO_ERROR;
+               goto done;
+       }
+
+done:
+       sdstd_wreg8(sd, SD_SoftwareReset,
+                   SFIELD(SFIELD(0, SW_RESET_DAT, 1), SW_RESET_CMD, 1));
+
+       retries = RETRIES_LARGE;
+       do {
+               rflags = sdstd_rreg8(sd, SD_SoftwareReset);
+               if (!GFIELD(rflags, SW_RESET_DAT) && !GFIELD(rflags, SW_RESET_CMD))
+                       break;
+       } while (--retries);
+
+       if (!retries) {
+               sd_err(("%s: Timeout waiting for DAT/CMD reset: 0x%02x\n",
+                       __FUNCTION__, rflags));
+               err = BCME_SDIO_ERROR;
+       }
+
+       return err;
+}
+
+extern int
+sdioh_abort(sdioh_info_t *sd, uint fnum)
+{
+       int ret;
+
+       sdstd_lock(sd);
+       ret = sdstd_abort(sd, fnum);
+       sdstd_unlock(sd);
+
+       return ret;
+}
+
+int
+sdioh_start(sdioh_info_t *sd, int stage)
+{
+       return SUCCESS;
+}
+
+int
+sdioh_stop(sdioh_info_t *sd)
+{
+       return SUCCESS;
+}
+
+static int
+sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg)
+{
+       uint16 regval;
+       uint retries;
+       uint function = 0;
+
+       /* If no errors, we're done */
+       if ((regval = sdstd_rreg16(sdioh_info, SD_ErrorIntrStatus)) == 0)
+               return SUCCESS;
+
+       sd_info(("%s: ErrorIntrStatus 0x%04x (clearing), IntrStatus 0x%04x PresentState 0x%08x\n",
+               __FUNCTION__, regval, sdstd_rreg16(sdioh_info, SD_IntrStatus),
+               sdstd_rreg(sdioh_info, SD_PresentState)));
+       sdstd_wreg16(sdioh_info, SD_ErrorIntrStatus, regval);
+
+       /* On command error, issue CMD reset */
+       if (regval & ERRINT_CMD_ERRS) {
+               sd_trace(("%s: issuing CMD reset\n", __FUNCTION__));
+               sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_CMD, 1));
+               for (retries = RETRIES_LARGE; retries; retries--)
+                       if (!(GFIELD(sdstd_rreg8(sdioh_info, SD_SoftwareReset), SW_RESET_CMD)))
+                               break;
+               if (!retries) {
+                       sd_err(("%s: Timeout waiting for CMD line reset\n", __FUNCTION__));
+               }
+       }
+
+       /* On data error, issue DAT reset */
+       if (regval & ERRINT_DATA_ERRS) {
+               sd_trace(("%s: issuing DAT reset\n", __FUNCTION__));
+               sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_DAT, 1));
+               for (retries = RETRIES_LARGE; retries; retries--)
+                       if (!(GFIELD(sdstd_rreg8(sdioh_info, SD_SoftwareReset), SW_RESET_DAT)))
+                               break;
+               if (!retries) {
+                       sd_err(("%s: Timeout waiting for DAT line reset\n", __FUNCTION__));
+               }
+       }
+
+       /* For an IO command (CMD52 or CMD53) issue an abort to the appropriate function */
+       if (cmd == SDIOH_CMD_53)
+               function = GFIELD(arg, CMD53_FUNCTION);
+       else if (cmd == SDIOH_CMD_52)
+       &nbs