#
# GNUmakefile for Linux
# Broadcom 802.11abg Networking Device Driver
#
# Copyright (C) 2009, Broadcom Corporation
# All Rights Reserved.
# 
# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
# the contents of this file may not be disclosed to third parties, copied
# or duplicated in any form, in whole or in part, without the prior
# written permission of Broadcom Corporation.
#
# Usage:
#
# make { [LINUXDIR=<path>] | [LINUXVER=<version>] }
#      [debug|nodebug]-[native|mipsel|mipseb|arm]-[<config file>]{-<config file>}
#
# <config file> is a file which is included by this makefile for the purpose of defining pre-defined make
#   variables.  These make variables are then converted to CC flags, file lists, etc which are used
#   to control the compilation, linking, etc.  These config files are by default in directory
#   .../src/wl/config and have a prefix wlconfig_lx_wl_.  For example <config file> "stadef" would include
#   file .../src/wl/config/wlconfig_lx_wl_stadef.  Multiple <config file>'s can be specified separated
#   by a - in which case they are included in the order specified before conversion.
#   In addition, these make variables can be set using the command line, e.g. make WLxxx=1 or by exporting to
#   the make process environment.  An important point is that assignments made in config files (or internally
#   by this script) will override initial make process environment variables but not command line specified
#   variables so be careful.
#
# If no make target is specified, a collection of various combinations of debug/nodebug and <config file>'s
#   for the "native" architecture will be built.
# 
# An object directory(s) of the form obj-<fully qualified target name>-$(LINUXVER) will be created in
#   the current directory and populated.  Typically this make file is invoked from its parent
#   directory .../src/wl/linux.
#  
#   The object directory will have these files 
#      *.o            bet you know what these are! :-)
#      wlcfg-obj      make variables resulting from inclusion of <config file>('s)
#      wlconf.h       sample (commented out) tunable parameters file (used if no <config file> appropriate option>)
#      Module.symvers (2.6 kernel only)  ??? 0 length file created by Linux 2.6 external kernel module framework
#      Makefile       (2.6 kernel only)  Linux 2.6 external kernel module make file
#      *.c            (2.6 kernels only) These are symbolic links to all .c's (not .h's) because using
#                       the Linux 2.6 external kernel module build framework requires all source in a single directory.
#
#   Note: The make file, object directory and source can be in different locations thorough judical use of
#   make's -C and -f options plus definition of make variable SRCBASE via the environment or a make command
#   line option,
#

#
# Description:
#
# Determines $(TARGETS) based command-line target or a default set; then
# selects each $(TARGET), creating an objdir and launching a submake.
#
# Phased operation:
#  1) For each cmdline target, generate a $(TARGETS) set for a submake.
#  2) Given $(TARGETS) list from (1), do an objdir submake for each $(TARGET).
#  3) Use $(TARGET) to build OBJDIR and wl config file, do submake in objdir.
#  4) Now $(INOBJDIR): read config and wl.mk for most flags/files settings,
#     may still use $(TARGET) for architecture and such.  Do dep, modules.
#
# $Id: Makefile,v 1.213.14.1.6.1 2009/08/22 02:56:48 Exp $
#

ifeq ($(TARGETS),)

ifeq ($(DEFBASICS),)
     #Default combinations
     DEFBASICS	:= apdef
     DEFBASICS	+= stadef
     DEFBASICS	+= apdef-stadef
     DEFBASICS	+= apdef-stadef-high
endif # DEFBASICS

DEBUGS := debug nodebug

DEFTARGETS = $(foreach dvar,$(DEBUGS),\
                $(patsubst %,$(dvar)-native-%,$(DEFBASICS)))

# Note: TARGETS command variable will be inherited through MAKEFLAGS to 
#       cause recursive makes to only see the else condition.

# Generate targets from command-line args, or use default set
.DEFAULT:
	@echo "Generating target(s) from $@"
	$(MAKE) EXPANDED=true TARGETS="$@" $@
default all:
	@echo "Using default target(s) $(DEFTARGETS)"
	$(MAKE) EXPANDED=true TARGETS="$(DEFTARGETS)" $(DEFTARGETS)
native mipsel mipseb arm:
	@echo "Using default target(s) for $@ architecture"
	$(MAKE) EXPANDED=true TARGETS="$(subst native,$@,$(DEFTARGETS))" \
		$(subst native,$@,$(DEFTARGETS))
clean:
	rm -rf obj-*

help:
	@echo "make [LINUXDIR=<path>] [LINUXVER=<version>]"
	@echo "     [debug|nodebug]-[native|mipsel|arm]-[<config>]"
	@echo
	@echo "     Use WLCFGDIR=x, WLCFG_PREFIX=y to override defaults of"
	@echo "     \$$(SRCBASE)/wl/config and wlconfig_lx_wl_ for <config>."
	@echo
	@echo "     A <config> is the \"basename\" of a configuration file,"
	@echo "     for example, \"native-stadef\" refers to the config file"
	@echo "     \$$(WLCFGDIR)/wlconfig_lx_wl_stadef (w/default prefix)."
	@echo
	@echo "     More than one <config> (e.g. native-apdef-stadef) may be"
	@echo "     specified; they concatenate into a single configuration."
	@echo "     If no target is specified, the ap/sta and debug/nodebug "
	@echo "     variants are built; specifying just an arch (e.g. arm)"
	@echo "     builds the variants for that architecture.  Otherwise"
	@echo "     at least one <config> must be specified."
	@echo
	@echo "examples:"
	@echo "  default set                    make"
	@echo "  default set for mips           make mipsel"
	@echo "  debug ap-sta                   make debug-apdef-stadef"
	@echo "  sta for specific linux         make LINUXVER=2.4.18-3 stadef"
	@echo

else # Targets available

# Setup LINUXDIR if not sepcified.  Use LINUXVER if specified to create
#   a LINUXDIR.  Use uname -r for LINUXVER ifuna, else use h
ifeq ($(LINUXDIR),)
ifeq ($(LINUXVER),)
# LINUXVER is  not specified, use temporarily uname for version
LINUXVER := $(shell uname -r)
#    $(warning LINUXVER is not defined, deriving using native LINUXVER=$(LINUXVER))
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
     $(warning LINUXDIR is set to native LINUXDIR=$(LINUXDIR))
endif
endif
endif # LINUXDIR

# Derive LINUXVER from LINUXDIR
MYKERNEL_RELEASE_KEYWORD:="KERNELRELEASE[[:space:]]*=.*kernel.release"
MYKERNEL_DEFINITION:=$(if \
  $(shell grep $(MYKERNEL_RELEASE_KEYWORD) $(LINUXDIR)/Makefile 2> /dev/null),\
  grep $(MYKERNEL_RELEASE_KEYWORD) $(LINUXDIR)/Makefile,\
  cat $(LINUXDIR)/Makefile)

LINUXVER:=$(shell ($(MYKERNEL_DEFINITION); echo "show_kernel_version_number$$$$:;@echo \$$(KERNELRELEASE)") 2> /dev/null | $(MAKE) --no-print-directory -k -C $(LINUXDIR) MYUNAME="" -f - show_kernel_version_number$$$$ 2> /dev/null)

ifeq ($(LINUXVER),)
     $(error LINUXVER=$(LINUXVER) is empty)
endif # LINUXVER

# check if 2.4 kernel or 2.5+ kernel
BCM_KVER:=$(shell echo $(LINUXVER) | cut -c1-3 | sed 's/2\.[56]/2\.6/')

# driver source base and C file path
ifeq ($(SRCBASE),)
  # Use current directory/../.. as SRCBASE if not defined.  
  # Remove potential trailing / in case anybody cuts and pastes ...
SRCBASE := $(patsubst %/,%,$(dir $(patsubst %/,%,$(dir $(patsubst %/,%,$(shell /bin/pwd))))))
endif # SRCBASE

vpath %.c $(SRCBASE)/wl/sys $(SRCBASE)/wl/linux $(SRCBASE)/shared $(SRCBASE)/bcmcrypto $(SRCBASE)/shared/nvram $(SRCBASE)/bcmsdio/sys

vpath %.o_shipped $(SRCBASE)/wl/sys $(SRCBASE)/wl/linux $(SRCBASE)/shared $(SRCBASE)/bcmcrypto $(SRCBASE)/shared/nvram $(SRCBASE)/bcmsdio/sys

# basic options, include current obj dir for wl driver config file
ifneq ($(findstring wluser,$(TARGET)),)
  DFLAGS := -DBCMPERFSTATS -DUSER_MODE
else # !wluser
  DFLAGS := -DLINUX
endif # TARGET=wluser

DFLAGS += -DSRCBASE=\"$(SRCBASE)\" -DBCMDRIVER

IFLAGS :=
ifneq ($(findstring wluser,$(TARGET)),)
  # Use specific LINUXVER include paths before native ones for usermode driver
  IFLAGS   += -isystem $(LINUXDIR)/usr/include
  IFLAGS   += -I.
  IFLAGS   += -I$(LINUXDIR)/include/asm/mach-default
else # !wluser
  IFLAGS   += -I$(LINUXDIR)/include
  ifneq ($(STBLINUX),1)
    ifeq ($(KERNELGE30),1)
       IFLAGS += -I$(LINUXDIR)/arch/x86/include
       IFLAGS += -I$(LINUXDIR)/arch/x86/include/asm
    else
        IFLAGS += -I$(LINUXDIR)/include/asm/mach-default
    endif
  else # STBLINUX
    ifeq ($(KERNELGE30),1)
        IFLAGS += -I$(LINUXDIR)/arch/mips/include
        IFLAGS += -I$(LINUXDIR)/arch/mips/include/asm/mach-generic
        IFLAGS += -I$(LINUXDIR)/arch/mips/include/asm/mach-brcmstb
    else
         IFLAGS += -I$(LINUXDIR)/include/asm/mach-generic
         IFLAGS += -I$(LINUXDIR)/include/asm/mach-brcmstb
    endif
  endif # STBLINUX
  IFLAGS   += -I.
endif # TARGET=wluser

IFLAGS   += -I$(SRCBASE)/wl/sys
IFLAGS   += -I$(SRCBASE)/include
IFLAGS   += -I$(SRCBASE)/shared

WFLAGS := -Wall -Wstrict-prototypes -Werror # -Wpointer-arith

# Use -Wmissing-prototypes, except for Linux 2.4.20-8 which had a warning in <fs.h>
#                           except for Linux 2.4.21-40 which had a warning in <quota.h>
#                           except for Linux 2.6.11-1 which had a warning in <div64.h>
NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS :=
NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS += 2.4.20-%
NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS += 2.4.21-%
NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS += 2.6.9-%
NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS += 2.6.11-%
ifeq (,$(filter $(NO_MISSING_PROTOTYPES_LINUXVER_PATTERNS),$(LINUXVER)))
WFLAGS += -Wmissing-prototypes
endif

LDFLAGS := -r
MODULES := wl.o
ifeq ($(BCM_KVER), 2.6)
  ##Kernel module names in 2.6 kernel have .ko suffix
  KMODULES:=wl.ko
  ifneq ($(findstring nintendo,$(TARGET)),)
    KMODULES := wlpci.ko
    ifneq ($(findstring nintendo-sdio,$(TARGET)),)
      KMODULES := wlsdio.ko
    endif
  else
    KMODULES := wl.ko
  endif
else # BCM_KVER!=2.6
  KMODULES:=$(MODULES)
endif # BCM_KVER

# some helpful variables
WLCFGDIR        ?= $(SRCBASE)/wl/config
WLCFG_PREFIX    ?= wlconfig_lx_wl_
WLTUNEFILE      ?= wltunable_sample.h

UPDATESH        := $(WLCFGDIR)/diffupdate.sh

WLCONF_DEF_FILE := $(WLCFGDIR)/wlconfig_lx_wl_feature
WLCONFFILE      := wlcfg-obj


########################################################
# Generate TARGETS if needed (first pass), else set
# TARGET to current TARGETS element and start build
# process with objdir (second pass).
#
# NOTE: #ifdef and #endif are mogrification if blocks
# NOTE: ifdef/ifeq/ifneq and endif (without '#') are 
#       makefile if blocks
########################################################

# Target portions recognized by make: arch and debug
ARCHES := native mipsel mipseb arm

DEBUGS := debug nodebug

###########################################################
# (TARGET) specified, determine OBJDIR and WLCONFS
###########################################################

# Directory name includes target
OBJDIR=obj-$(TARGET)-$(LINUXVER)

# Split apart make and config stuff
INMAKE:= $(filter $(DEBUGS) $(ARCHES),$(subst -, ,$(TARGET)))
WLCONFS:=$(filter-out $(INMAKE),$(subst -, ,$(TARGET)))

############################################################
# In the objdir, actual building takes place.  Set the
# required variables by setting basic options, getting
# more from the config file, and using wl.mk to map to
# flags and files.  Some arch/debug stuff done here.
############################################################

ifeq ($(INOBJDIR),true)
  # Set basic config options for Linux WL
  WL=1
  #TODO# # Some of these wluser/umk enablers can go to wlconfig area
  ifneq ($(findstring wluser,$(TARGET)),)
    WLUM=1
    OSLUM=1
  else # !wluser
  WLLX=1
  WLLXIW=1
  OSLLX=1
    ifneq ($(findstring wlumk,$(TARGET)),)
      WLUMK=1
    endif # wlumk
  endif

  ifneq ($(filter debug,$(INMAKE)),)
    DEBUG=1
  endif
  ifeq ($(filter mipsel,$(INMAKE)),)
    WLLXNOMIPSEL=1
  endif

  # Get remaining WL config, set flags and files
  include $(WLCONFFILE)
  include $(WLCFGDIR)/wl.mk

  ifeq ($(WLFILES),)
    $(error WLFILES is not defined)
  endif

  ifeq ($(BCMJTAG),1)
    WLTUNEFILE = wltunable_jtag.h
  endif

  # Remove duplicate filenames, pick up flags
  CFILES := $(sort $(WLFILES))
  DFLAGS += $(WLFLAGS)

  # Set some arch-specific definitions
  ifneq ($(filter mipsel,$(INMAKE)),)
    CROSS_COMPILE := mipsel-linux-
    ifneq ($(wildcard $(SRCBASE)/linux/linux),)
      # Reset LINUXDIR and LINUXVER for cross builds
      LINUXDIR := $(SRCBASE)/linux/linux
      LINUXVER := $(shell $(MAKE) --no-print-directory -s -C $(LINUXDIR) script 'SCRIPT=@echo $$(KERNELRELEASE)')
    endif
  else
    ifneq ($(filter mipseb,$(INMAKE)),)
      CROSS_COMPILE ?= mips-linux-
      DFLAGS += -DIL_BIGENDIAN
      ifneq ($(filter nodebug,$(INMAKE)),)
        LDFLAGS += -S
      endif
    endif
    ifneq ($(filter arm,$(INMAKE)),)
      CROSS_COMPILE ?= armeb-linux-
      DFLAGS += -DIL_BIGENDIAN
      ifneq ($(filter nodebug,$(INMAKE)),)
        LDFLAGS += -S
      endif
    endif
  endif

  # CROSS_COMPILE was decided by arch
  CC := $(CROSS_COMPILE)gcc
  LD := $(CROSS_COMPILE)ld
  NM := $(CROSS_COMPILE)nm
  OBJCOPY := $(CROSS_COMPILE)objcopy
  STRIP   := $(CROSS_COMPILE)strip

  OFILES := $(CFILES:.c=.o) $(WLFILES_O)
  # Add our custom CFLAGS
  CFLAGS += $(DFLAGS) $(IFLAGS) $(WFLAGS)

  # Divine CFLAGS from kernel source
ifneq ($(BCM_KVER), 2.6)
  CFLAGS += $(shell $(MAKE) --no-print-directory -s -C $(LINUXDIR) script BCMINTERNAL= 'SCRIPT=@echo $$(CFLAGS) $$(MODFLAGS) $$(NOSTDINC_FLAGS)')

  else # BCM_KVER=2.6

    # the kernel will compile the module itself. So the flags are defined, 
    # except for __KERNEL__ !
    ifeq ($(findstring wluser,$(TARGET)),)
  CFLAGS += -D__KERNEL__
    endif
  # we need to export this so the make from the kernel can know it
  WLCFLAGS = $(CFLAGS) -I$(shell pwd)
  export WLCFLAGS
  WLOFILES := $(OFILES)
  export WLOFILES
  endif # BCM_KVER

endif # INOBJDIR==true

############################################################
# Check if the dongle image is embedded
############################################################

ifeq ($(BCMEMBEDIMAGE),1)
	DNGL_IMAGE_NAME ?= 4322-bmac/roml-ag-nodis
	DNGL_IMAGE_PATH := $(SRCBASE)/dongle/rte/wl/builds/$(DNGL_IMAGE_NAME)
	DFLAGS += -DBCMEMBEDIMAGE=\"$(DNGL_IMAGE_PATH)/rtecdc.h\"
endif

########################################################
# TARGET is one of completed $(TARGETS)
########################################################

$(TARGETS):
	$(MAKE) TARGET=$@ objdir

objdir:
	@echo "Making objdir: TARGET=$(TARGET), level $(MAKELEVEL) kernel $(BCM_KVER)"
	install -d $(OBJDIR)

        # Generate WL config file
	cat $(foreach config,$(WLCONFS),$(WLCFGDIR)/$(WLCFG_PREFIX)$(config)) > \
		$(OBJDIR)/$(WLCONFFILE)
        ifneq ($(findstring wluser,$(TARGET)),)
	  # Build dependencies
	  $(MAKE) -C $(OBJDIR) -f $(SRCBASE)/wl/linux/Makefile SRCBASE=$(SRCBASE) INOBJDIR=true dep
	  # Build usermodel wl driver app
	  $(MAKE) -C $(OBJDIR) -f $(SRCBASE)/wl/linux/Makefile SRCBASE=$(SRCBASE) INOBJDIR=true wlumdrv
        else # !wluser
	  # Build dependencies
	  $(MAKE) -C $(OBJDIR) -f $(SRCBASE)/wl/linux/Makefile SRCBASE=$(SRCBASE) INOBJDIR=true dep

	  # Build modules
	  $(MAKE) -C $(OBJDIR) -f $(SRCBASE)/wl/linux/Makefile SRCBASE=$(SRCBASE) INOBJDIR=true modules
        endif # wluser

wlconf.h: $(WLCFGDIR)/$(WLTUNEFILE) force
	[ ! -f $@ ] || chmod +w $@
	@echo "check and update config file"
	cp $< wltemp
	$(UPDATESH) wltemp $@

# These following targets are called by release makefiles 
# These are intended to provide a list of wl-files and flags given a wl target
# Lookup linux-wl.mk for examples

showwlconf:
	@echo "WLTUNEFILE [$(TARGET)]= $(WLTUNEFILE)"
	@echo "WLFILES    [$(TARGET)]= $(WLFILES)"
	@echo "WLFLAGS    [$(TARGET)]= $(WLFLAGS)"
	@echo "LINUXVER   [$(TARGET)]= $(LINUXVER)"
	@echo "LINUXDIR   [$(TARGET)]= $(LINUXDIR)"
	@echo "----------------------------------"

showwlfiles:
	@echo "$(WLFILES)"

showwlfiles_src:
	@echo "$(WLFILES_SRC)"

showwlflags:
	@echo "$(WLFLAGS)"

# Show compiler version, for the current target build
showenv:
	@echo "CC = $(CC) (ver=`$(CC) -dumpversion`; host=`hostname`; processor=`uname -m`)"
ifneq ($(findstring wluser,$(TARGET)),)
	# For wluser targets, there needs to be <LINUXDIR>/usr/include
	@if [ ! -d "$(LINUXDIR)/usr/include" ]; then \
	    echo "" \
	    $(warning WARN: Missing $(LINUXDIR)/usr/include) \
	    $(warning WARN: for TARGET=$(TARGET)) \
	    $(warning WARN: Native /usr/include will be used instead) \
	    $(warning WARN: $(LINUXDIR)/usr/include needs to be populated); \
	fi
endif # TARGET=wluser

ifneq ($(findstring wluser,$(TARGET)),)

wlumdrv: $(WLOFILES)
	# Link final userlevel driver binary/app. Iteratively search libraries
	# until all symbols are resolved
	$(CC) --verbose -o $@ $^ -L$(LINUXDIR)/usr/lib \
		--start-group -lgcc -lrt -lpci -lpthread -lz -lc --end-group

endif # TARGET=wluser

ifeq ($(BCM_KVER), 2.6)

modules: $(OFILES)
	test -r ./Makefile || ln -s $(SRCBASE)/wl/linux/makefile.26 ./Makefile
	$(MAKE) -C $(LINUXDIR) M=$(shell pwd) $(if $(VERBOSE),V=1) modules

else # BCM_KVER!=2.4

modules: $(MODULES)

endif # BCM_KVER

# Dependencies
dep: showenv wlconf.h $(if $(SHOWWLCONF),showwlconf) $(if $(VERBOSE),showwlconf)
dep: $(foreach file,$(CFILES),.$(file).depend)
#dep: $(foreach file,$(CFILES),.$(file).preprocessor)

ifneq ($(BCM_KVER), 2.6)
# THE module
wl.o: $(OFILES)
	$(LD) $(LDFLAGS) -o $@ $^
endif


.PHONY: native all objdir dep modules clean force $(foreach objdir,$(TARGETS),$(objdir)-$(LINUXVER))

.%.c.depend: %.c
	$(CC) $(CFLAGS) -M $< > $@

.%.c.preprocessor: %.c
	$(CC) -E -C $(CFLAGS) $< > $@
#	$(CC) -S $(CFLAGS) $< 

#.%.c.depend::
#	touch $@

ifeq ($(BCM_KVER), 2.6)
# when make is called from 2.6, vpath doesn't work so we need to link the files.
%.o: %.c
	test -r ./$< || ln -s $< .
%.o: %.o_shipped
	test -r ./$< || ln -s $< .

ifneq ($(findstring wluser,$(TARGET)),)

%.o: %.c
	$(CC) $(CFLAGS) -g -c -o $@ $<

endif # wluser

else # BCM_KVER!=2.6

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<
	@( \
	echo 'ifneq ($$(CFLAGS),$(CFLAGS))' ; \
	echo '$@: force' ; \
	echo 'endif' ; \
	) > .$*.c.flags

endif # BCM_KVER

force:

ifneq ($(wildcard .*.depend),)
include $(wildcard .*.depend)
endif
ifneq ($(wildcard .*.flags),)
include $(wildcard .*.flags)
endif

endif # TARGETS
