ADHD: Daemon for watching A/V device events

Details

  o Adds infrastructure to handle different threads w/ automatic startup.

   Threads are declared with THREAD_DESCRIPTOR, and the system
   infrastructure handles all the startup and management.

  o Adds signal handling infrastructure; restarts threads on SIGHUP.

  o Added command line argument processing.

    Note that, at least, Goobuntu has a defect in getopt_long().

       --option <optional-argument>

   will yield a SEGV because 'optarg' is NULL.

          --option=<optional-argument>

   works, however.

Testing

  Execute 'make' in the 'adhd' directory, and the project builds.
  Execute 'gavd', and note the message output.

BUG=chromium-os:19558
TEST=See above

Change-Id: I1033af5690fac0052c1892a81e296b3d2538ae88
Signed-off-by: Taylor Hutt <thutt@chromium.org>
diff --git a/Makefile b/Makefile
index dca6bfb..82cbf70 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,9 @@
 
 all:	gavd
 
-gavd:				# Google Audio Visual Daemon
+gavd::	lib
+
+lib gavd::				# Google Audio Visual Daemon
 	@$(call remake,$@)
 
 clean:
diff --git a/defs/c.mk b/defs/c.mk
index 801298a..fe10cc2 100644
--- a/defs/c.mk
+++ b/defs/c.mk
@@ -6,7 +6,8 @@
 
 
 COPTIONS =					\
-	-O3					\
+	-g					\
+	-O2					\
 	-funit-at-a-time
 
 # Compiler is too old to support
@@ -15,6 +16,18 @@
 #	-Wlarger-than=4096
 #	-Wsync-nand
 
+# Enable GC on unused functions and data
+CGC	=					\
+	-ffunction-sections			\
+	-fdata-sections
+
+# Also need to link with '-Xlinker --library=pthread'.
+PTHREAD	= 					\
+	-pthread
+
+LDGC	=					\
+	-Xlinker --gc-sections
+
 CWARN	=					\
 	-Waddress				\
 	-Waggregate-return			\
@@ -57,7 +70,6 @@
 	-Woverlength-strings			\
 	-Woverride-init				\
 	-Wpacked				\
-	-Wpadded				\
 	-Wparentheses				\
 	-Wpointer-arith				\
 	-Wpointer-sign				\
@@ -82,7 +94,6 @@
 	-Wundef					\
 	-Wuninitialized				\
 	-Wunknown-pragmas			\
-	-Wunreachable-code			\
 	-Wunsafe-loop-optimizations		\
 	-Wunused-function			\
 	-Wunused-label				\
@@ -101,12 +112,15 @@
 BOARD_INCLUDE	= -DADHD_BOARD_INCLUDE='"board-generic.h"'
 endif
 
-INCLUDES =	-I$(ADHD_DIR)/include
+INCLUDES	=				\
+		-I$(ADHD_DIR)/include		\
+		-I$(ADHD_SOURCE_DIR)
 
 CFLAGS	=					\
-	-ansi					\
+	-std=gnu99				\
+	-MD \
 	$(INCLUDES)				\
+	$(PTHREADS)				\
 	$(BOARD_INCLUDE)			\
-	$(CWARN) $(COPTIONS)
-
-
+	-DBOARD='"$(BOARD)"'			\
+	$(CWARN) $(COPTIONS) $(CGC) $(LDGC)
diff --git a/defs/make.mk b/defs/make.mk
index 5a10df9..615d10e 100644
--- a/defs/make.mk
+++ b/defs/make.mk
@@ -19,6 +19,8 @@
 export ADHD_BUILD_DIR	= $(ADHD_DIR)/build/development
 endif
 
+GAVD_LIB	= $(ADHD_BUILD_DIR)/lib/gavd.a
+
 # mkdir: Creates a directory, and all its parents, if it does not exist.
 #
 mkdir	= [ ! -d $(1) ] &&			\
@@ -40,4 +42,5 @@
 		-f $(ADHD_DIR)/$(1)/Makefile		\
 		-C $(ADHD_BUILD_DIR)/$(1)		\
 		VPATH=$(ADHD_DIR)/$(1)			\
+		ADHD_SOURCE_DIR=$(ADHD_DIR)/$(1)	\
 		$(1)
diff --git a/defs/utilities.mk b/defs/utilities.mk
index 954ce73..3a3c06d 100644
--- a/defs/utilities.mk
+++ b/defs/utilities.mk
@@ -10,4 +10,5 @@
 # This makes it easy to ensure there are no host OS utility
 # dependencies when cross compiling.
 
-MKDIR	= mkdir
+MKDIR	= /bin/mkdir
+AR	= /usr/bin/ar
diff --git a/gavd/Makefile b/gavd/Makefile
index a5c8da2..d438b5e 100644
--- a/gavd/Makefile
+++ b/gavd/Makefile
@@ -3,10 +3,18 @@
 # found in the LICENSE file.
 include $(ADHD_DIR)/defs/definitions.mk
 
-CFILES	= main.c
+CFILES	=					\
+	main.c					\
+	signal_handling.c			\
+	thread_management.c			\
+	thread_gpio_headphone.c
+
 OFILES	= $(CFILES:.c=.o)
-LIBS	=
+LIBS	= $(GAVD_LIB)
 
 gavd:	$(OFILES) $(LIBS)
-	$(CC) -o $@ $(OFILES) $(LIBS)
+	$(CC) -o $@ $(OFILES) $(LIBS) \
+		-Xlinker --library=pthread \
+		-Xlinker --script=$(ADHD_SOURCE_DIR)/ld.script
 
+-include *.d
diff --git a/include/board-x86-mario.h b/gavd/board-amd64-generic.h
similarity index 78%
rename from include/board-x86-mario.h
rename to gavd/board-amd64-generic.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-amd64-generic.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-tegra2_seaboard.h b/gavd/board-arm-generic.h
similarity index 89%
rename from include/board-tegra2_seaboard.h
rename to gavd/board-arm-generic.h
index afe7983..e0f3478 100644
--- a/include/board-tegra2_seaboard.h
+++ b/gavd/board-arm-generic.h
@@ -4,4 +4,7 @@
  */
 #if !defined(_BOARD_TEGRA2_SEA_BOARD_H_)
 #define _BOARD_TEGRA2_SEA_BOARD_H_
+
+#undef ADHD_GPIO_HEADPHONE
+
 #endif
diff --git a/include/board-lumpy.h b/gavd/board-lumpy.h
similarity index 78%
rename from include/board-lumpy.h
rename to gavd/board-lumpy.h
index 98c0eeb..388f6d1 100644
--- a/include/board-lumpy.h
+++ b/gavd/board-lumpy.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_LUMPY_H_)
 #define _BOARD_LUMPY_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-stumpy.h b/gavd/board-stumpy.h
similarity index 78%
rename from include/board-stumpy.h
rename to gavd/board-stumpy.h
index 109754b..fb627d3 100644
--- a/include/board-stumpy.h
+++ b/gavd/board-stumpy.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_STUMPY_H_)
 #define _BOARD_STUMPY_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-tegra2_aebl.h b/gavd/board-tegra2_aebl.h
similarity index 76%
copy from include/board-tegra2_aebl.h
copy to gavd/board-tegra2_aebl.h
index fd505b2..16397ed 100644
--- a/include/board-tegra2_aebl.h
+++ b/gavd/board-tegra2_aebl.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_AEBL_H_)
 #define _BOARD_TEGRA2_AEBL_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-tegra2_aebl.h b/gavd/board-tegra2_arthur.h
similarity index 76%
copy from include/board-tegra2_aebl.h
copy to gavd/board-tegra2_arthur.h
index fd505b2..16397ed 100644
--- a/include/board-tegra2_aebl.h
+++ b/gavd/board-tegra2_arthur.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_AEBL_H_)
 #define _BOARD_TEGRA2_AEBL_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-tegra2_asymptote.h b/gavd/board-tegra2_asymptote.h
similarity index 77%
rename from include/board-tegra2_asymptote.h
rename to gavd/board-tegra2_asymptote.h
index 02eb6b2..adff541 100644
--- a/include/board-tegra2_asymptote.h
+++ b/gavd/board-tegra2_asymptote.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_ASYMPTOTE_H_)
 #define _BOARD_TEGRA2_ASYMPTOTE_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-tegra2_aebl.h b/gavd/board-tegra2_dev-board-opengl.h
similarity index 88%
rename from include/board-tegra2_aebl.h
rename to gavd/board-tegra2_dev-board-opengl.h
index fd505b2..94a1b85 100644
--- a/include/board-tegra2_aebl.h
+++ b/gavd/board-tegra2_dev-board-opengl.h
@@ -4,4 +4,7 @@
  */
 #if !defined(_BOARD_TEGRA2_AEBL_H_)
 #define _BOARD_TEGRA2_AEBL_H_
+
+#undef ADHD_GPIO_HEADPHONE
+
 #endif
diff --git a/include/board-tegra2_aebl.h b/gavd/board-tegra2_dev-board.h
similarity index 88%
copy from include/board-tegra2_aebl.h
copy to gavd/board-tegra2_dev-board.h
index fd505b2..94a1b85 100644
--- a/include/board-tegra2_aebl.h
+++ b/gavd/board-tegra2_dev-board.h
@@ -4,4 +4,7 @@
  */
 #if !defined(_BOARD_TEGRA2_AEBL_H_)
 #define _BOARD_TEGRA2_AEBL_H_
+
+#undef ADHD_GPIO_HEADPHONE
+
 #endif
diff --git a/include/board-tegra2_aebl.h b/gavd/board-tegra2_generic.h
similarity index 88%
copy from include/board-tegra2_aebl.h
copy to gavd/board-tegra2_generic.h
index fd505b2..94a1b85 100644
--- a/include/board-tegra2_aebl.h
+++ b/gavd/board-tegra2_generic.h
@@ -4,4 +4,7 @@
  */
 #if !defined(_BOARD_TEGRA2_AEBL_H_)
 #define _BOARD_TEGRA2_AEBL_H_
+
+#undef ADHD_GPIO_HEADPHONE
+
 #endif
diff --git a/include/board-tegra2_kaen.h b/gavd/board-tegra2_kaen.h
similarity index 76%
rename from include/board-tegra2_kaen.h
rename to gavd/board-tegra2_kaen.h
index 48e115b..49debb6 100644
--- a/include/board-tegra2_kaen.h
+++ b/gavd/board-tegra2_kaen.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_KAEN_H_)
 #define _BOARD_TEGRA2_KAEN_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-tegra2_seaboard.h b/gavd/board-tegra2_seaboard.h
similarity index 77%
copy from include/board-tegra2_seaboard.h
copy to gavd/board-tegra2_seaboard.h
index afe7983..1aac002 100644
--- a/include/board-tegra2_seaboard.h
+++ b/gavd/board-tegra2_seaboard.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_SEA_BOARD_H_)
 #define _BOARD_TEGRA2_SEA_BOARD_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-tegra2_seaboard.h b/gavd/board-tegra2_wario.h
similarity index 77%
copy from include/board-tegra2_seaboard.h
copy to gavd/board-tegra2_wario.h
index afe7983..1aac002 100644
--- a/include/board-tegra2_seaboard.h
+++ b/gavd/board-tegra2_wario.h
@@ -4,4 +4,8 @@
  */
 #if !defined(_BOARD_TEGRA2_SEA_BOARD_H_)
 #define _BOARD_TEGRA2_SEA_BOARD_H_
+
+#define ADHD_GPIO_HEADPHONE
+#define ADHD_GPIO_HEADPHONE_GPIO_NUMBER 185
+
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-agz
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-agz
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-agz
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-alex.h b/gavd/board-x86-alex.h
similarity index 78%
rename from include/board-x86-alex.h
rename to gavd/board-x86-alex.h
index aa504a1..fa48df3 100644
--- a/include/board-x86-alex.h
+++ b/gavd/board-x86-alex.h
@@ -4,4 +4,5 @@
  */
 #if !defined(_BOARD_X86_ALEX_H_)
 #define _BOARD_X86_ALEX_H_
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-dogfood.h
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-dogfood.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-dogfood.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-fruitloop.h
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-fruitloop.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-fruitloop.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-generic
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-generic
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-generic
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-mario.h
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-mario.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-mario.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-mario64.h
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-mario64.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-mario64.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-mario.h b/gavd/board-x86-pineview.h
similarity index 78%
copy from include/board-x86-mario.h
copy to gavd/board-x86-pineview.h
index 9ed5049..8e66d6f 100644
--- a/include/board-x86-mario.h
+++ b/gavd/board-x86-pineview.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_MARIO_H_)
 #define _BOARD_X86_MARIO_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/include/board-x86-zgb.h b/gavd/board-x86-zgb.h
similarity index 78%
rename from include/board-x86-zgb.h
rename to gavd/board-x86-zgb.h
index 123cd86..fcfd48b 100644
--- a/include/board-x86-zgb.h
+++ b/gavd/board-x86-zgb.h
@@ -4,4 +4,6 @@
  */
 #if !defined(_BOARD_X86_ZGB_H_)
 #define _BOARD_X86_ZGB_H_
+
+#undef  ADHD_GPIO_HEADPHONE     /* No GPIO headphone switch. */
 #endif
diff --git a/gavd/board.h b/gavd/board.h
new file mode 100644
index 0000000..6b647c1
--- /dev/null
+++ b/gavd/board.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#if !defined(_BOARD_GENERIC_H_)
+#define _BOARD_GENERIC_H_
+
+#define ADHD_TARGET_MACHINE BOARD
+#include ADHD_BOARD_INCLUDE
+
+#if !defined(ADHD_GPIO_HEADPHONE)
+#define adhd_gpio_headphone 0
+#undef ADHD_GPIO_HEADPHONE_GPIO_NUMBER
+#else
+#define adhd_gpio_headphone 1
+#if !defined(ADHD_GPIO_HEADPHONE_GPIO_NUMBER)
+#error "ADHD_GPIO_HEADPHONE_GPIO_NUMBER must be defined."
+#endif
+#endif
+#endif
diff --git a/gavd/ld.script b/gavd/ld.script
new file mode 100644
index 0000000..63a97de
--- /dev/null
+++ b/gavd/ld.script
@@ -0,0 +1,214 @@
+/* This script was generated by using '-Xlinker --verbose' on a gcc command line.
+ * It was then hand-modified to add the '.thread_info' section.
+ */
+
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  .hash           : { *(.hash) }
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+      *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
+      *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
+      *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
+      *(.rela.ifunc)
+    }
+  .rela.plt       :
+    {
+      *(.rela.plt)
+      PROVIDE_HIDDEN (__rela_iplt_start = .);
+      *(.rela.iplt)
+      PROVIDE_HIDDEN (__rela_iplt_end = .);
+    }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .plt            : { *(.plt) *(.iplt) }
+  .text           :
+  {
+    *(.text.unlikely .text.*_unlikely)
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x90909090
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE_HIDDEN (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got) *(.igot) }
+  . = DATA_SEGMENT_RELRO_END (24, .);
+  .got.plt        : { *(.got.plt)  *(.igot.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 64 / 8 : 1);
+  }
+  .lbss   :
+  {
+    *(.dynlbss)
+    *(.lbss .lbss.* .gnu.linkonce.lb.*)
+    *(LARGE_COMMON)
+  }
+  . = ALIGN(64 / 8);
+  .lrodata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+  {
+    *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+  }
+  .ldata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+  {
+    *(.ldata .ldata.* .gnu.linkonce.l.*)
+    . = ALIGN(. != 0 ? 64 / 8 : 1);
+  }
+  .thread_descriptor : {
+      __thread_descriptor_beg = . ;
+      *(.thread_descriptor)
+      __thread_descriptor_end = . ;
+  }
+  . = ALIGN(64 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/gavd/main.c b/gavd/main.c
index b397141..4834ad2 100644
--- a/gavd/main.c
+++ b/gavd/main.c
@@ -3,11 +3,108 @@
  * found in the LICENSE file.
  */
 
+#include <errno.h>
+#include <getopt.h>
 #include <stdio.h>
-#include ADHD_BOARD_INCLUDE
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "verbose.h"
+#include "signal_handling.h"
+#include "thread_management.h"
+#include "board.h"
 
-int main(void)
+static const char * const program_name = "gavd";
+
+static void help(void)
 {
-    printf("Google A/V Daemon\n");
+    /* TODO(thutt): Add help */
+}
+
+static void process_arguments(int argc, char **argv)
+{
+    static struct option options[] = {
+        {
+            .name    = "help",
+            .has_arg = no_argument,
+            .flag    = NULL,
+            .val     = 256
+        },
+        {
+            .name    = "verbose",
+            .has_arg = optional_argument,
+            .flag    = NULL,
+            .val     = 257
+        },
+    };
+
+    while (1) {
+        int option_index = 0;
+        const int choice = getopt_long(argc, argv, "", options, &option_index);
+
+        if (choice == -1) {
+            break;
+        }
+
+        switch (choice) {
+        case 256:
+            help();
+            break;
+
+        case 257:
+            /* Goobuntu has a defect with 'optarg'.  If '--verbose 1'
+             * is used, 'optarg' will be NULL.  Use '--verbose=1'.
+             */
+            verbose_set((unsigned)atoi(optarg));
+            break;
+
+        default:
+            printf("?? getopt returned character code 0%o ??\n", choice);
+        }
+    }
+}
+
+static void daemonize(void)
+{
+    pid_t child_pid;
+
+    child_pid = fork();
+    if (child_pid != 0) {
+        verbose_log(0, LOG_INFO, "Child process: '%u'.", child_pid);
+        exit(0);
+    }
+
+    /* Now running as daemon.
+     *
+     * TODO(thutt): Detach from console.
+     * TODO(thutt): close stdin/stdout/stderr
+     */
+    verbose_log(0, LOG_INFO, "%s: started", __FUNCTION__);
+    if (chdir("/") != 0) {
+        verbose_log(0, LOG_ERR, "Failed to chdir('/')");
+        exit(-errno);
+    }        
+
+    signal_start();
+    threads_start();
+
+    while(!threads_quit_daemon()) {
+        sleep(3);
+    }
+    
+    verbose_log(0, LOG_INFO, "%s: stopped", program_name);
+}
+
+int main(int argc, char **argv)
+{
+    process_arguments(argc, argv);
+    verbose_initialize(program_name);
+
+    verbose_log(0, LOG_INFO, "compiled for target machine: '%s'",
+                ADHD_TARGET_MACHINE);
+
+    daemonize();
+
+    verbose_finalize();
     return 0;
 }
diff --git a/gavd/signal_handling.c b/gavd/signal_handling.c
new file mode 100644
index 0000000..13e9ade
--- /dev/null
+++ b/gavd/signal_handling.c
@@ -0,0 +1,66 @@
+
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#include "verbose.h"
+#include "thread_management.h"
+#include "signal_handling.h"
+
+static void signal_handle_sighup(int        signum,
+                                 siginfo_t *siginfo,
+                                 void      *ucontext)
+{
+    verbose_log(8, LOG_INFO, "%s", __FUNCTION__);
+    signum   = signum;          /* Silence compiler warning. */
+    siginfo  = siginfo;         /* Silence compiler warning. */
+    ucontext = ucontext;        /* Silence compiler warning. */
+    threads_kill_all();
+    threads_start();
+}
+
+static void signal_start_sighup(void)
+{
+    struct sigaction action;
+    sigset_t         sa_mask;
+
+    sigemptyset(&sa_mask);
+    action.sa_mask      = sa_mask;
+    action.sa_flags     = SA_SIGINFO; /* Use sa.sigaction, not sa_handler. */
+    action.sa_sigaction = signal_handle_sighup;
+    sigaction(SIGHUP, &action, NULL);
+}
+
+static void signal_handle_sigterm(int        signum,
+                                  siginfo_t *siginfo,
+                                  void      *ucontext)
+{
+    verbose_log(8, LOG_INFO, "%s", __FUNCTION__);
+    signum   = signum;          /* Silence compiler warning. */
+    siginfo  = siginfo;         /* Silence compiler warning. */
+    ucontext = ucontext;        /* Silence compiler warning. */
+    thread_management.quit = 1;
+}
+
+static void signal_start_sigterm(void)
+{
+    struct sigaction action;
+    sigset_t         sa_mask;
+
+    sigemptyset(&sa_mask);
+    action.sa_mask      = sa_mask;
+    action.sa_flags     = SA_SIGINFO; /* Use sa.sigaction, not sa_handler. */
+    action.sa_sigaction = signal_handle_sigterm;
+    sigaction(SIGTERM, &action, NULL);
+}
+
+void signal_start(void)
+{
+    verbose_log(5, LOG_INFO, "%s", __FUNCTION__);
+    signal_start_sighup();
+    signal_start_sigterm();
+}
diff --git a/include/board-x86-zgb.h b/gavd/signal_handling.h
similarity index 66%
copy from include/board-x86-zgb.h
copy to gavd/signal_handling.h
index 123cd86..7b0dfab 100644
--- a/include/board-x86-zgb.h
+++ b/gavd/signal_handling.h
@@ -2,6 +2,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#if !defined(_BOARD_X86_ZGB_H_)
-#define _BOARD_X86_ZGB_H_
+#if !defined(_SIGNAL_HANDLING_H_)
+#define _SIGNAL_HANDLING_H_
+
+void signal_start(void);
 #endif
diff --git a/gavd/thread_gpio_headphone.c b/gavd/thread_gpio_headphone.c
new file mode 100644
index 0000000..ff2b434
--- /dev/null
+++ b/gavd/thread_gpio_headphone.c
@@ -0,0 +1,29 @@
+
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <assert.h>
+#include <unistd.h>
+
+#include "board.h"
+
+#if defined(ADHD_GPIO_HEADPHONE)
+#include "verbose.h"
+#include "thread_management.h"
+
+
+static void *gpio_headphone(void *arg)
+{
+    verbose_log(5, LOG_INFO, "%s: start", __FUNCTION__);
+    arg = arg;                  /* Silence compiler warning. */
+
+    while (!thread_management.exit) {
+        sleep(1);
+    }
+    verbose_log(5, LOG_INFO, "%s exited", __FUNCTION__);
+    return NULL;
+}
+
+THREAD_DESCRIPTOR("GPIO Headphone", gpio_headphone);
+#endif
diff --git a/gavd/thread_management.c b/gavd/thread_management.c
new file mode 100644
index 0000000..62e47d2
--- /dev/null
+++ b/gavd/thread_management.c
@@ -0,0 +1,73 @@
+
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <assert.h>
+#include <pthread.h>
+#include <limits.h>
+
+#include "board.h"
+#include "verbose.h"
+#include "thread_management.h"
+
+extern unsigned char __thread_descriptor_beg;
+extern unsigned char __thread_descriptor_end;
+
+thread_management_t thread_management;
+
+static unsigned threads_number_of_descriptors(void)
+{
+    unsigned long length = ((unsigned long)(&__thread_descriptor_end -
+                                            &__thread_descriptor_beg) /
+                            sizeof(thread_descriptor_t));
+
+    assert(length <= UINT_MAX);
+    return (unsigned)length;
+}
+
+static thread_descriptor_t *threads_first_descriptor(void)
+{
+    return (thread_descriptor_t *)&__thread_descriptor_beg;
+}
+
+static thread_descriptor_t *threads_last_descriptor(void)
+{
+    unsigned             n    = threads_number_of_descriptors();
+    thread_descriptor_t *desc = threads_first_descriptor() + (n - 1);
+    return desc;
+}
+
+void threads_start(void)
+{
+    thread_descriptor_t *desc = threads_first_descriptor();
+    unsigned             n    = threads_number_of_descriptors();
+
+    thread_management.exit = 0;
+    thread_management.quit = 0;
+    while (n-- > 0) {
+        verbose_log(1, LOG_INFO, "%s: '%s'", __FUNCTION__, desc->name);
+        pthread_create(&desc->thread, NULL, desc->start_routine, desc);
+        ++desc;
+    }
+}
+
+void threads_kill_all(void)
+{
+    /* Threads are killed in the reverse order of creation. */
+    unsigned             n    = threads_number_of_descriptors();
+    thread_descriptor_t *desc = threads_last_descriptor();
+
+    thread_management.exit = 1;
+    while (n-- > 0) {
+        verbose_log(5, LOG_INFO, "%s: '%s'", __FUNCTION__, desc->name);
+        pthread_join(desc->thread, NULL);
+        --desc;
+    }
+    thread_management.exit = 0;
+}
+
+unsigned threads_quit_daemon(void)
+{
+    return thread_management.quit;
+}
diff --git a/gavd/thread_management.h b/gavd/thread_management.h
new file mode 100644
index 0000000..e51972d
--- /dev/null
+++ b/gavd/thread_management.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#if !defined(_THREAD_MANAGEMENT_H_)
+#define _THREAD_MANAGEMENT_H_
+#include <pthread.h>
+
+typedef struct thread_descriptor_t {
+    void       *(*start_routine)(void*); /* pthread start routine */
+    const char *name;
+
+    pthread_t   thread;
+    void       *data;
+} thread_descriptor_t;
+
+#define THREAD_DESCRIPTOR(_name, _start_routine)                \
+    thread_descriptor_t                                         \
+    __attribute__((section(".thread_descriptor")))              \
+    __thread_descriptor_##_start_routine = {                    \
+        .name          = _name,                                 \
+        .start_routine = _start_routine,                        \
+    }
+
+typedef struct thread_management_t {
+    unsigned      quit;         /* quit == 0 => Daemon continues to run.
+                                 * quit      != 1 => Daemon exits.
+                                 */
+    unsigned      exit;         /* exit == 0 => Continue running.
+                                 * exit      != 0 => Thread should exit.
+                                 *
+                                 * There is no mutex controlling this
+                                 * data because it is written by one
+                                 * function.  All readers will exit
+                                 * when a non-zero value is present.
+                                 */
+} thread_management_t;
+
+extern thread_management_t thread_management;
+
+void threads_start(void);
+void threads_kill_all(void);
+unsigned threads_quit_daemon(void);
+#endif
diff --git a/include/board-generic.h b/include/board-generic.h
deleted file mode 100644
index 9e11a19..0000000
--- a/include/board-generic.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#if !defined(_BOARD_GENERIC_H_)
-#define _BOARD_GENERIC_H_
-#endif
diff --git a/include/verbose.h b/include/verbose.h
new file mode 100644
index 0000000..9faab43
--- /dev/null
+++ b/include/verbose.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#if !defined(_VERBOSE_H_)
+#define _VERBOSE_H_
+#include <syslog.h>
+
+/* verbose_set: Set verbosity of the daemon.
+ *
+ *  verbosity: The new level of verbosity.
+ *             Higher levels mean more diagnostic output will be produced.
+ *             If not called, the verbosity level is 0.
+ *
+ * A verbosity level of 0 means minimal output.
+ */
+void verbose_set(unsigned verbosity);
+
+/* verbose_log: Log information using syslog
+ *
+ *   verbosity_level : Message is logged only if 'level <= current
+ *                     verbosity level'.
+ *   log_level       : LOG_EMERG      system is unusable
+ *                     LOG_ALERT      action must be taken immediately
+ *                     LOG_CRIT       critical conditions
+ *                     LOG_ERR        error conditions
+ *                     LOG_WARNING    warning conditions
+ *                     LOG_NOTICE     normal, but significant, condition
+ *                     LOG_INFO       informational message
+ *                     LOG_DEBUG      debug-level message
+ *   format: printf()-style format specifier
+ *   ...   : arguments to use in expansion of 'format'.
+ */
+void verbose_log(unsigned    verbosity_level,
+                 int         log_level,
+                 const char *format,
+                 ...)
+    __attribute__((format(printf, 3, 4)));
+
+void verbose_initialize(const char *program_name);
+void verbose_finalize(void);
+#endif
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 0000000..d2684f4
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,13 @@
+# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+include $(ADHD_DIR)/defs/definitions.mk
+
+CFILES	=					\
+	verbose.c
+
+OFILES	= $(CFILES:.c=.o)
+
+lib:	$(OFILES)
+	$(AR) -r $(GAVD_LIB) $(OFILES) 2>/dev/null
+
diff --git a/lib/verbose.c b/lib/verbose.c
new file mode 100644
index 0000000..2522a52
--- /dev/null
+++ b/lib/verbose.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include "verbose.h"
+
+static unsigned  verbose_level = 0;
+static const int log_options   = LOG_NDELAY | LOG_PID;
+static const int log_facility  = LOG_DAEMON; /* /var/log/daemon.log */
+static char      log_buffer[1024];
+
+
+void verbose_set(unsigned verbosity)
+{
+    verbose_level = verbosity;
+}
+
+void verbose_initialize(const char *program_name)
+{
+    openlog(program_name, log_options, log_facility);
+}
+
+void verbose_finalize(void)
+{
+    closelog();
+}
+
+
+/*
+ *  log_level values:
+*/
+void verbose_log(unsigned    verbosity_level,
+                 int         log_level,
+                 const char *format,
+                 ...)
+{
+    if (verbosity_level <= verbose_level) {
+        const size_t log_buffer_len = (sizeof(log_buffer) /
+                                       sizeof(log_buffer[0]));
+        va_list ap;
+
+        va_start(ap, format);
+        vsnprintf(log_buffer, log_buffer_len, format, ap);
+        log_buffer[log_buffer_len - 1] = '\0';
+        va_end(ap);
+        syslog(log_facility | log_level, "%s", log_buffer);
+    }
+}